diff --git a/vtl-engine/pom.xml b/vtl-engine/pom.xml index 363a402f1..adb05296e 100644 --- a/vtl-engine/pom.xml +++ b/vtl-engine/pom.xml @@ -44,10 +44,17 @@ commons-text 1.10.0 + - com.github.hervian - safety-mirror - 4.0.1 + org.projectlombok + lombok + 1.18.12 + provided + + + org.jetbrains + annotations + 20.1.0 @@ -77,6 +84,13 @@ 8 8 + + + org.projectlombok + lombok + 1.18.12 + + diff --git a/vtl-engine/src/main/java/fr/insee/vtl/engine/VtlNativeMethods.java b/vtl-engine/src/main/java/fr/insee/vtl/engine/VtlNativeMethods.java index cdc544539..835d9c25d 100644 --- a/vtl-engine/src/main/java/fr/insee/vtl/engine/VtlNativeMethods.java +++ b/vtl-engine/src/main/java/fr/insee/vtl/engine/VtlNativeMethods.java @@ -1,6 +1,6 @@ package fr.insee.vtl.engine; -import com.github.hervian.reflection.Fun; +import fr.insee.vtl.engine.utils.safetymirror.Fun; import fr.insee.vtl.model.utils.Java8Helpers; import fr.insee.vtl.engine.visitors.expression.*; import fr.insee.vtl.engine.visitors.expression.functions.ComparisonFunctionsVisitor; @@ -12,7 +12,6 @@ import java.lang.reflect.Method; import java.time.*; -import java.time.temporal.ChronoUnit; import java.util.Set; public class VtlNativeMethods { diff --git a/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/Delegate.java b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/Delegate.java new file mode 100644 index 000000000..d228f4b2b --- /dev/null +++ b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/Delegate.java @@ -0,0 +1,936 @@ +package fr.insee.vtl.engine.utils.safetymirror; + +import lombok.NonNull; +import lombok.SneakyThrows; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + *
+ * Copyright 2016 Anders Granau Høfft
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * END OF NOTICE
+ * 
+ * @author Anders Granau Høfft + */ +public abstract class Delegate> { + + private List methodRefs = new LinkedList<>(); + public enum InvocationStrategy { + THROW_EXCEPTIONS, + CATCH_AND_AGGREGATE_EXCEPTIONS; + } + + /** + * Please notice that null entries are simply ignored/discarded. + * @param methodRefs Array of Method References to add to the delegate, typically defined using the double colon syntax, MyClassOrObject::myMethod + */ + public Delegate(METHOD_REF[] methodRefs) { + add(methodRefs); + } + + public List getMethodRefs() { + return Collections.unmodifiableList(methodRefs); + } + + + protected abstract RETURN invoke(METHOD_REF function, Object... args) throws Exception; + + protected DelegateInvocationResult invoke(Object... args) throws Exception { + return invoke(InvocationStrategy.THROW_EXCEPTIONS, args); + } + + @SneakyThrows //Invocation exceptions are caught in the invokeMethodReferences method. Adding SneakyThrows annotation to avoid compiler error - but no exceptions are expected here. + protected DelegateInvocationResult invokeAndAggregateExceptions(Object... args) { + return invoke(InvocationStrategy.CATCH_AND_AGGREGATE_EXCEPTIONS, args); + } + + protected DelegateInvocationResult invoke(InvocationStrategy invocationStrategy, Object... args) throws Exception { + return invokeMethodReferences(invocationStrategy, args); + } + + //TODO: Synchronous vs Asynchronous raising? See C# guide: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/events/ + private DelegateInvocationResult invokeMethodReferences(InvocationStrategy invocationStrategy, Object... args) throws Exception { + DelegateInvocationResult.DelegateInvocationResultBuilder delegateInvocationResultBuilder = DelegateInvocationResult.builder(); + boolean oneOrMoreExceptionsThrown = false; + for (METHOD_REF m : getMethodRefs()) { + FunctionInvocationResult.FunctionInvocationResultBuilder builder = FunctionInvocationResult.builder(); + builder.method(m.toMethod()); + try { + Object result = invoke(m, args); + builder.result(result); + } catch (Exception e) { + oneOrMoreExceptionsThrown = true; + if (InvocationStrategy.THROW_EXCEPTIONS == invocationStrategy) { + throw e; + } else { + builder.exception(e); + } + } + delegateInvocationResultBuilder.oneOrMoreExceptionsThrown(oneOrMoreExceptionsThrown); + delegateInvocationResultBuilder.functionInvocationResult(builder.build()); + } + + return delegateInvocationResultBuilder.build(); + } + + //TODO Make thread safe? + /** + *
+     * Method to add a function to the delegate (i.e. to the delegate's underlying
+     * list of functions).
+     * Be aware that you need to add the function as a Fun reference variable
+     * if you want to be able to remove i later on - that is, you need the reference.
+     *
+     * Examples:
+     *
+     * This will work:
+     *    Fun.With0Params<String> myFunction = "   hello world  "::trim;
+     *    Delegate.With0Params<String> myDelegate = new Delegate.With0Params(myFunction);
+     *    myDelegate.remove(myFunction);
+     *
+     * This won't work:
+     *    Delegate.With0Params<String> myDelegate = new Delegate.With0Params("   hello world  "::trim);
+     *    myDelegate.remove("   hello world  "::trim);
+     * 
+ * @param methodRefVarArg Array or vararg of Method References to add to the delegate, typically defined using the double colon syntax, MyClassOrObject::myMethod + */ + @SafeVarargs + public final void add(METHOD_REF... methodRefVarArg){ + if (methodRefVarArg!=null){ + for (METHOD_REF methodRef: methodRefVarArg){ + if (methodRef != null) { + methodRefs.add(methodRef); + } + } + } + } + + //TODO Make thread safe? + /** + *
+     * Method to remove function from delegate (i.e. from the delegate's underlying
+     * list of functions).
+     * Be aware that you need to add the function as a Fun reference variable
+     * in order to be able to remove it.
+     *
+     * Examples:
+     *
+     * This will work:
+     *    Fun.With0Params<String> myFunction = "   hello world  "::trim;
+     *    Delegate.With0Params<String> myDelegate = new Delegate.With0Params(myFunction);
+     *    myDelegate.remove(myFunction);
+     *
+     * This won't work:
+     *    Delegate.With0Params<String> myDelegate = new Delegate.With0Params("   hello world  "::trim);
+     *    myDelegate.remove("   hello world  "::trim);
+     * 
+ * + * @param methodRefVarArg Array or vararg of Method References to add to the delegate, typically defined using the double colon syntax, MyClassOrObject::myMethod + * @return a boolean indicating whether or not anything was removed, i.e. if a match was found. + */ + @SafeVarargs + public final boolean remove(METHOD_REF... methodRefVarArg){ + boolean removed = false; + if (methodRefVarArg!=null){ + for (METHOD_REF methodRef: methodRefVarArg){ + if (methodRef != null) { + removed = methodRefs.removeIf(e -> e.equals(methodRef)); + } + } + } + return removed; + } + + + + //********************************* STATIC NESTED CLASSES FROM HERE ONWARDS ***************************************/ + + public static class With0Params extends Delegate> { + public @SafeVarargs With0Params(Fun.With0Params... methodRefs) { + super(methodRefs); + } + + /** + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke() throws Exception { + return super.invoke(); + } + + /** + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + */ + public DelegateInvocationResult invokeAndAggregateExceptions() { + return super.invokeAndAggregateExceptions(); + } + + @Override + protected RETURN invoke(Fun.With0Params function, Object... args) throws Exception { + return function.invoke(); + } + } + + + public static class With0ParamsAndVoid extends Delegate> { + public With0ParamsAndVoid(Fun.With0ParamsAndVoid... methodRefs) { + super(methodRefs); + } + + /** + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke() throws Exception { + return super.invoke(); + } + + /** + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + */ + public DelegateInvocationResult invokeAndAggregateExceptions() { + return super.invokeAndAggregateExceptions(); + } + + @Override + protected Void invoke(Fun.With0ParamsAndVoid function, Object... args) throws Exception { + function.invoke(); + return null; + } + } + + + public static class With1Param extends Delegate> { + public With1Param(Fun.With1Param... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1) throws Exception { + return super.invoke(param1); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1) { + return super.invokeAndAggregateExceptions(param1); + } + + @Override + protected RETURN invoke(Fun.With1Param function, Object... args) throws Exception { + return function.invoke(args==null ? null : (PARAM1)args[0]); + } + } + + public static class With1ParamAndVoid extends Delegate> { + public With1ParamAndVoid(Fun.With1ParamAndVoid... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1) throws Exception { + return super.invoke(param1); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1) { + return super.invokeAndAggregateExceptions(param1); + } + + @Override + protected Void invoke(Fun.With1ParamAndVoid function, Object... args) throws Exception { + function.invoke(args==null ? null : (PARAM1)args[0]); + return null; + } + } + + + public static class With2Params extends Delegate> { + public With2Params(Fun.With2Params... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2) throws Exception { + return super.invoke(param1, param2); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2) { + return super.invokeAndAggregateExceptions(param1, param2); + } + + @Override + protected RETURN invoke(Fun.With2Params function, Object... args) throws Exception { + return function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1]); + } + } + + public static class With2ParamsAndVoid extends Delegate> { + public With2ParamsAndVoid(Fun.With2ParamsAndVoid... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2) throws Exception { + return super.invoke(param1, param2); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2) { + return super.invokeAndAggregateExceptions(param1, param2); + } + + @Override + protected Void invoke(Fun.With2ParamsAndVoid function, Object... args) throws Exception { + function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1]); + return null; + } + } + + + public static class With3Params extends Delegate> { + public With3Params(Fun.With3Params... methodRefs) { + super(methodRefs); + } + + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3) throws Exception { + return super.invoke(param1, param2, param3); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3) { + return super.invokeAndAggregateExceptions(param1, param2, param3); + } + + @Override + protected RETURN invoke(Fun.With3Params function, Object... args) throws Exception { + return function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2]); + } + } + + public static class With3ParamsAndVoid extends Delegate> { + public With3ParamsAndVoid(Fun.With3ParamsAndVoid... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3) throws Exception { + return super.invoke(param1, param2, param3); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3) { + return super.invokeAndAggregateExceptions(param1, param2, param3); + } + + @Override + protected Void invoke(Fun.With3ParamsAndVoid function, Object... args) throws Exception { + function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2]); + return null; + } + } + + + public static class With4Params extends Delegate> { + public With4Params(Fun.With4Params... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4) throws Exception { + return super.invoke(param1, param2, param3, param4); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4) { + return super.invokeAndAggregateExceptions(param1, param2, param3, param4); + } + + @Override + protected RETURN invoke(Fun.With4Params function, Object... args) throws Exception { + return function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2], (PARAM4)args[3]); + } + } + + public static class With4ParamsAndVoid extends Delegate> { + public With4ParamsAndVoid(Fun.With4ParamsAndVoid... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4) throws Exception { + return super.invoke(param1, param2, param3, param4); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4) { + return super.invokeAndAggregateExceptions(param1, param2, param3, param4); + } + + @Override + protected Void invoke(Fun.With4ParamsAndVoid< PARAM1, PARAM2, PARAM3, PARAM4> function, Object... args) throws Exception { + function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2], (PARAM4)args[3]); + return null; + } + } + + + public static class With5Params extends Delegate> { + public With5Params(Fun.With5Params... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5) throws Exception { + return super.invoke(param1, param2, param3, param4, param5); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5) { + return super.invokeAndAggregateExceptions(param1, param2, param3, param4, param5); + } + + @Override + protected RETURN invoke(Fun.With5Params function, Object... args) throws Exception { + return function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2], (PARAM4)args[3], (PARAM5)args[4]); + } + } + + public static class With5ParamsAndVoid extends Delegate> { + public With5ParamsAndVoid(Fun.With5ParamsAndVoid... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5) throws Exception { + return super.invoke(param1, param2, param3, param4, param5); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5) { + return super.invokeAndAggregateExceptions(param1, param2, param3, param4, param5); + } + + @Override + protected Void invoke(Fun.With5ParamsAndVoid function, Object... args) throws Exception { + function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2], (PARAM4)args[3], (PARAM5)args[4]); + return null; + } + } + + + public static class With6Params extends Delegate> { + public With6Params(Fun.With6Params... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6) throws Exception { + return super.invoke(param1, param2, param3, param4, param5, param6); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6) { + return super.invokeAndAggregateExceptions(param1, param2, param3, param4, param5, param6); + } + + @Override + protected RETURN invoke(Fun.With6Params function, Object... args) throws Exception { + return function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2], (PARAM4)args[3], (PARAM5)args[4], (PARAM6)args[5]); + } + } + + public static class With6ParamsAndVoid extends Delegate> { + public With6ParamsAndVoid(Fun.With6ParamsAndVoid... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6) throws Exception { + return super.invoke(param1, param2, param3, param4, param5, param6); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6) { + return super.invokeAndAggregateExceptions(param1, param2, param3, param4, param5, param6); + } + + @Override + protected Void invoke(Fun.With6ParamsAndVoid function, Object... args) throws Exception { + function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2], (PARAM4)args[3], (PARAM5)args[4], (PARAM6)args[5]); + return null; + } + } + + + public static class With7Params extends Delegate> { + public With7Params(Fun.With7Params... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @param param7 the seventh argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7) throws Exception { + return super.invoke(param1, param2, param3, param4, param5, param6, param7); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @param param7 the seventh argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7) { + return super.invokeAndAggregateExceptions(param1, param2, param3, param4, param5, param6, param7); + } + + @Override + protected RETURN invoke(Fun.With7Params function, Object... args) throws Exception { + return function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2], (PARAM4)args[3], (PARAM5)args[4], (PARAM6)args[5], (PARAM7)args[6]); + } + } + + public static class With7ParamsAndVoid extends Delegate> { + public With7ParamsAndVoid(Fun.With7ParamsAndVoid... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @param param7 the seventh argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7) throws Exception { + return super.invoke(param1, param2, param3, param4, param5, param6, param7); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @param param7 the seventh argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7) { + return super.invokeAndAggregateExceptions(param1, param2, param3, param4, param5, param6, param7); + } + + @Override + protected Void invoke(Fun.With7ParamsAndVoid function, Object... args) throws Exception { + function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2], (PARAM4)args[3], (PARAM5)args[4], (PARAM6)args[5], (PARAM7)args[6]); + return null; + } + } + + + public static class With8Params extends Delegate> { + public With8Params(Fun.With8Params... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @param param7 the seventh argument to the underlying method(s) + * @param param8 the eighth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8) throws Exception { + return super.invoke(param1, param2, param3, param4, param5, param6, param7, param8); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @param param7 the seventh argument to the underlying method(s) + * @param param8 the eighth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8) { + return super.invokeAndAggregateExceptions(param1, param2, param3, param4, param5, param6, param7, param8); + } + + @Override + protected RETURN invoke(Fun.With8Params function, Object... args) throws Exception { + return function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2], (PARAM4)args[3], (PARAM5)args[4], (PARAM6)args[5], (PARAM7)args[6], (PARAM8)args[7]); + } + } + + public static class With8ParamsAndVoid extends Delegate> { + public With8ParamsAndVoid(Fun.With8ParamsAndVoid... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @param param7 the seventh argument to the underlying method(s) + * @param param8 the eighth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8) throws Exception { + return super.invoke(param1, param2, param3, param4, param5, param6, param7, param8); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @param param7 the seventh argument to the underlying method(s) + * @param param8 the eighth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8) { + return super.invokeAndAggregateExceptions(param1, param2, param3, param4, param5, param6, param7, param8); + } + + @Override + protected Void invoke(Fun.With8ParamsAndVoid function, Object... args) throws Exception { + function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2], (PARAM4)args[3], (PARAM5)args[4], (PARAM6)args[5], (PARAM7)args[6], (PARAM8)args[7]); + return null; + } + } + + + public static class With9Params extends Delegate> { + public With9Params(Fun.With9Params... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @param param7 the seventh argument to the underlying method(s) + * @param param8 the eighth argument to the underlying method(s) + * @param param9 the ninth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8, @NonNull @NotNull PARAM9 param9) throws Exception { + return super.invoke(param1, param2, param3, param4, param5, param6, param7, param8, param9); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @param param7 the seventh argument to the underlying method(s) + * @param param8 the eighth argument to the underlying method(s) + * @param param9 the ninth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8, @NonNull @NotNull PARAM9 param9) { + return super.invokeAndAggregateExceptions(param1, param2, param3, param4, param5, param6, param7, param8, param9); + } + + @Override + protected RETURN invoke(Fun.With9Params function, Object... args) throws Exception { + return function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2], (PARAM4)args[3], (PARAM5)args[4], (PARAM6)args[5], (PARAM7)args[6], (PARAM8)args[7], (PARAM9)args[8]); + } + } + + public static class With9ParamsAndVoid extends Delegate> { + public With9ParamsAndVoid(Fun.With9ParamsAndVoid... methodRefs) { + super(methodRefs); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @param param7 the seventh argument to the underlying method(s) + * @param param8 the eighth argument to the underlying method(s) + * @param param9 the ninth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + * @throws Exception if one of the invoked functions throws an Exception + */ + public DelegateInvocationResult invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8, @NonNull @NotNull PARAM9 param9) throws Exception { + return super.invoke(param1, param2, param3, param4, param5, param6, param7, param8, param9); + } + + /** + * @param param1 the first argument to the underlying method(s) + * @param param2 the second argument to the underlying method(s) + * @param param3 the third argument to the underlying method(s) + * @param param4 the fourth argument to the underlying method(s) + * @param param5 the fifth argument to the underlying method(s) + * @param param6 the sixth argument to the underlying method(s) + * @param param7 the seventh argument to the underlying method(s) + * @param param8 the eighth argument to the underlying method(s) + * @param param9 the ninth argument to the underlying method(s) + * @return a {@link DelegateInvocationResult} containing all the results of the invoked functions + * @throws NullPointerException if one or more of the arguments are null + */ + public DelegateInvocationResult invokeAndAggregateExceptions(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8, @NonNull @NotNull PARAM9 param9) { + return super.invokeAndAggregateExceptions(param1, param2, param3, param4, param5, param6, param7, param8, param9); + } + + @Override + protected Void invoke(Fun.With9ParamsAndVoid function, Object... args) throws Exception { + function.invoke(args==null ? null : (PARAM1)args[0], (PARAM2)args[1], (PARAM3)args[2], (PARAM4)args[3], (PARAM5)args[4], (PARAM6)args[5], (PARAM7)args[6], (PARAM8)args[7], (PARAM9)args[8]); + return null; + } + } + + + /** + * Interface class created to be used in Lombok's @lombok.experimental.Delegate annotation as an argument to the 'excludes' annotation type member. + * The idea is that one can create a C# like 'event' by annotating a private Delegate field with @lombok.experimental.Delegate(excludes=Delegator.IDelegator.class) + * Going forward we hope that Lombok will support creating meta annotations, in which case this project could create an @Event annotation that lombok would then view as @Delegate(excludes=Delegator.IDelegator.class). + * + * Please notice that for now, the preferred way of creating an event is + * by A) making the Delegate private (so that only the definer can invoke it) + * and by B) Creating a public Event (by providing the Delegate to the constructor) + */ + public interface IDelegator { + void invoke(); + void invokeAndAggregateExceptions(); + List getMethodRefs(); + } + +} \ No newline at end of file diff --git a/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/DelegateInvocationResult.java b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/DelegateInvocationResult.java new file mode 100644 index 000000000..4006fa180 --- /dev/null +++ b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/DelegateInvocationResult.java @@ -0,0 +1,46 @@ +package fr.insee.vtl.engine.utils.safetymirror; + +import lombok.Builder; +import lombok.Getter; +import lombok.Singular; + +import java.util.Collections; +import java.util.List; + +/** + *
+ * Copyright 2016 Anders Granau Høfft
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * END OF NOTICE
+ * 
+ * @author Anders Granau Høfft + */ +@Builder +public class DelegateInvocationResult { + + @Getter + private boolean oneOrMoreExceptionsThrown; + + @Singular + private List> functionInvocationResults; //TODO: Return immutable copy in the getter? + + public FunctionInvocationResult get(int index){ + return getFunctionInvocationResults().get(index); + } + + public List> getFunctionInvocationResults(){ + return Collections.unmodifiableList(functionInvocationResults); + } + +} diff --git a/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/Event.java b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/Event.java new file mode 100644 index 000000000..5f2136a84 --- /dev/null +++ b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/Event.java @@ -0,0 +1,193 @@ +package fr.insee.vtl.engine.utils.safetymirror; + +/** + *
+ *  Copyright 2016 Anders Granau Høfft
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  END OF NOTICE
+ *
+ *
+ * This class is a wrapper around a Delegator. It limits the number of public methods.
+ * The idea is to create a C#-like 'event', where subscribers can only add and remove
+ * events but where the publisher (i.e. the class declaring the event) have full
+ * control of the underlying delegate. In other words: only the publisher can invoke
+ * the delegate's method references (a.k.a. publish the event).
+ * 
Examples: + * + * Example 1: + * Let's create a private Delegate but expose the add() and remove() method + * by creating a public Event field, that wraps the Delegator: + * + * private Delegator.With0Params<String> delegator = Delegator.with0Params(); + * public Event.With0Params<String> event = Event.with0Params(delegator); + * + * Example 2: + * Another way to expose the add and remove method only is by using + * Project Lombok's Delegate annotation, as such: + * + * {@literal @}lombok.experimental.Delegate(excludes = Delegator.IDelegator.class) + * private Delegator.With0Params<String> delegator = Delegator.with0Params(); + * + * With this approach we do not need the Event field, since Lombok generates + * a public add() and remove() method directly in the declaring class. + * Of course, this approach requires that your project uses Lombok. + * As it stands, the Event approach is more easily remembered, however, + * if Lombok at some point creates the possibility of meta-annotations, + * this project will create an Event annnotation that would simplify above. + * Until that happens, using the Event class is the preferred way to create an'event'. + *
+ * @param the return type + * @param the method reference + * @author Anders Granau Høfft + */ +public abstract class Event> { + + private Delegate delegate; + + private Event(Delegate delegate){ + this.delegate = delegate; + } + + public void add(METHOD_REF... methodRefVarArg){ + delegate.add(methodRefVarArg); + } + + public boolean remove(METHOD_REF... methodRefVarArg){ + return delegate.remove(methodRefVarArg); + } + + + //********************************* STATIC NESTED CLASSES FROM HERE ONWARDS ***************************************/ + + public static class With0Params extends Event> { + public With0Params(Delegate.With0Params delegator) { + super(delegator); + } + } + + public static class With0ParamsAndVoid extends Event> { + public With0ParamsAndVoid(Delegate.With0ParamsAndVoid delegator) { + super(delegator); + } + } + + public static class With1Param extends Event> { + public With1Param(Delegate.With1Param delegator) { + super(delegator); + } + } + + public static class With1ParamAndVoid extends Event> { + public With1ParamAndVoid(Delegate.With1ParamAndVoid delegator) { + super(delegator); + } + } + + public static class With2Params extends Event> { + public With2Params(Delegate.With2Params delegator) { + super(delegator); + } + } + + public static class With2ParamsAndVoid extends Event> { + public With2ParamsAndVoid(Delegate.With2ParamsAndVoid delegator) { + super(delegator); + } + } + + public static class With3Params extends Event> { + public With3Params(Delegate.With3Params delegator) { + super(delegator); + } + } + + public static class With3ParamsAndVoid extends Event> { + public With3ParamsAndVoid(Delegate.With3ParamsAndVoid delegator) { + super(delegator); + } + } + + public static class With4Params extends Event> { + public With4Params(Delegate.With4Params delegator) { + super(delegator); + } + } + + public static class With4ParamsAndVoid extends Event> { + public With4ParamsAndVoid(Delegate.With4ParamsAndVoid delegator) { + super(delegator); + } + } + + public static class With5Params extends Event> { + public With5Params(Delegate.With5Params delegator) { + super(delegator); + } + } + + public static class With5ParamsAndVoid extends Event> { + public With5ParamsAndVoid(Delegate.With5ParamsAndVoid delegator) { + super(delegator); + } + } + + public static class With6Params extends Event> { + public With6Params(Delegate.With6Params delegator) { + super(delegator); + } + } + + public static class With6ParamsAndVoid extends Event> { + public With6ParamsAndVoid(Delegate.With6ParamsAndVoid delegator) { + super(delegator); + } + } + + public static class With7Params extends Event> { + public With7Params(Delegate.With7Params delegator) { + super(delegator); + } + } + + public static class With7ParamsAndVoid extends Event> { + public With7ParamsAndVoid(Delegate.With7ParamsAndVoid delegator) { + super(delegator); + } + } + + public static class With8Params extends Event> { + public With8Params(Delegate.With8Params delegator) { + super(delegator); + } + } + + public static class With8ParamsAndVoid extends Event> { + public With8ParamsAndVoid(Delegate.With8ParamsAndVoid delegator) { + super(delegator); + } + } + + public static class With9Params extends Event> { + public With9Params(Delegate.With9Params delegator) { + super(delegator); + } + } + + public static class With9ParamsAndVoid extends Event> { + public With9ParamsAndVoid(Delegate.With9ParamsAndVoid delegator) { + super(delegator); + } + } + +} diff --git a/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/Fun.java b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/Fun.java new file mode 100644 index 000000000..43b4040fa --- /dev/null +++ b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/Fun.java @@ -0,0 +1,883 @@ +package fr.insee.vtl.engine.utils.safetymirror; + +import com.github.hervian.reflection.util.SerializedLambdaToMethod; +import lombok.NonNull; +import lombok.SneakyThrows; +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; +import java.lang.reflect.Method; + +/** + *
+ * Copyright 2016 Anders Granau Høfft
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * END OF NOTICE
+ *
+ *
+ * Fun, short for Function, is a super interface that from a user perspective is used as part of a fluent API
+ * in signatures that accepts Method References.
+ * I.e. one writes 'Fun.' and then choose the appropriate nested class such as 'Fun.With2Params'.
+ * (In most IDEs you can simply type Fun.W2 to get the autocomplete to suggest 'Fun.With2Params'.)
+ *
+ * Notice that you must supply the signatures return value and parameters in the generics,
+ * fx: 'Fun.With2Params<Double, Integer, String> for methods that
+ * given an Integer and a String (in that order) returns a Double.
+ *
+ * Note that since capital 'Void' is NOT a boxed lower case 'void' we need to give method references
+ * with return type void special attention. In other words, current Java versions won't accept generics with
+ * primitives, including void, but for all primitives except void, this is ok since fx 'Fun.With2Params<Double>
+ * will match primitive signatures due to autoboxing. But for void as return type we must use a special subclass and
+ * write code like fx: 'Fun.With2ParamsAndVoid<Double>
+ * Note also, that this may (or may not) change once Project Valhalla is completed and specialized Generics
+ * become part of the Java Language Specification. See https://en.wikipedia.org/wiki/Project_Valhalla_(Java_language).
+ *
+ * Besides the fluent API described above (i.e. the subinterfaces that allow you to pass around functions and
+ * use them as types), the Fun interface contains a large number of overloaded methods.
+ * The overloading is actually an implementation detail.
+ * From a user perspective you should consider the Fun type to have the following API:
+ *
+ * java.lang.Method method = Fun.toMethod(SomeClassOrObject::someMethod);
+ *
+ * Please be aware that there are 2 situations where you must help the compiler choose the correct overloaded method.
+ *
+ * 1.
+ * When targeting an overloaded  method you must help the compiler choose the correct overloaded toMethod method
+ * by specifying the parameters and return value in generics. This is fx the case with this call:
+ * Fun.<String>toMethod(Class::forName)
+ *
+ * 2.
+ * When targeting a method with varargs you must cast the Method Reference to help the compiler choose
+ * the correct overloaded toMethod method, Fx:
+ * Method m = Fun.toMethod((Fun.With1ParamAndVoid<String[]>)new FunToMethodTest()::methodThatTakesAVarargParam);
+ *
+ * 
+ * @author Anders Granau Høfft + */ +public interface Fun extends Serializable { + + default Method toMethod(){ + return SerializedLambdaToMethod.createMethodFromSuperConsumer(this); + } + + /** + *
+     * Usage:
+     * java.lang.Method method = Fun.toMethod(SomeClassOrObject::someMethod);
+     *
+     * Don't worry too much about the large number of overloaded toMethod methods. The overloading is an implementation
+     * detail. That being said, pay attention to below corner cases.
+     *
+     * Please be aware that there are 2 situations where you must help the compiler choose the correct overloaded method.
+     *
+     * 1.
+     * When targeting an overloaded  method you must help the compiler choose the correct overloaded toMethod method
+     * by specifying the parameters and return value in generics. This is fx the case with this call:
+     * Fun.<String>toMethod(Class::forName)
+     *
+     * 2.
+     * When targeting a method with varargs you must cast the Method Reference to help the compiler choose
+     * the correct overloaded toMethod method, Fx:
+     * Method m = Fun.toMethod((Fun.With1ParamAndVoid<String[]>)new FunToMethodTest()::methodThatTakesAVarargParam);
+     *
+     * 
+ * @see Fun + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param a dummy generic to help the compiler choose the correct overloaded toMethod method. + * @return a {@link Method} instance that corresponds to the method reference. Please note, though, that the Method instance will *NOT* return the correct method name. Use Fun.getName for this purpose. + */ + static Method toMethod(Fun.With0ParamsAndVoid methodRef) { return SerializedLambdaToMethod.createMethodFromSuperConsumer(methodRef); } + + /** + * @see Fun#toMethod(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return a {@link Method} instance that corresponds to the method reference. Please note, though, that the Method instance will *NOT* return the correct method name. Use Fun.getName for this purpose. + */ + static Method toMethod(Fun.With1ParamAndVoid methodRef) { return SerializedLambdaToMethod.createMethodFromSuperConsumer(methodRef); } + /** + * @see Fun#toMethod(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return a {@link Method} instance that corresponds to the method reference. Please note, though, that the Method instance will *NOT* return the correct method name. Use Fun.getName for this purpose. + */ + static Method toMethod(Fun.With2ParamsAndVoid methodRef) { return SerializedLambdaToMethod.createMethodFromSuperConsumer(methodRef); } + /** + * @see Fun#toMethod(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return a {@link Method} instance that corresponds to the method reference. Please note, though, that the Method instance will *NOT* return the correct method name. Use Fun.getName for this purpose. + */ + static Method toMethod(Fun.With3ParamsAndVoid methodRef) { return SerializedLambdaToMethod.createMethodFromSuperConsumer(methodRef); } + /** + * @see Fun#toMethod(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return a {@link Method} instance that corresponds to the method reference. Please note, though, that the Method instance will *NOT* return the correct method name. Use Fun.getName for this purpose. + */ + static Method toMethod(Fun.With4ParamsAndVoid methodRef) { return SerializedLambdaToMethod.createMethodFromSuperConsumer(methodRef); } + /** + * @see Fun#toMethod(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return a {@link Method} instance that corresponds to the method reference. Please note, though, that the Method instance will *NOT* return the correct method name. Use Fun.getName for this purpose. + */ + static Method toMethod(Fun.With5ParamsAndVoid methodRef) { return SerializedLambdaToMethod.createMethodFromSuperConsumer(methodRef); } + /** + * @see Fun#toMethod(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return a {@link Method} instance that corresponds to the method reference. Please note, though, that the Method instance will *NOT* return the correct method name. Use Fun.getName for this purpose. + */ + static Method toMethod(Fun.With6ParamsAndVoid methodRef) { return SerializedLambdaToMethod.createMethodFromSuperConsumer(methodRef); } + /** + * @see Fun#toMethod(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return a {@link Method} instance that corresponds to the method reference. Please note, though, that the Method instance will *NOT* return the correct method name. Use Fun.getName for this purpose. + */ + static Method toMethod(Fun.With7ParamsAndVoid methodRef) { return SerializedLambdaToMethod.createMethodFromSuperConsumer(methodRef); } + /** + * @see Fun#toMethod(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return a {@link Method} instance that corresponds to the method reference. Please note, though, that the Method instance will *NOT* return the correct method name. Use Fun.getName for this purpose. + */ + static Method toMethod(Fun.With8ParamsAndVoid methodRef) { return SerializedLambdaToMethod.createMethodFromSuperConsumer(methodRef); } + /** + * @see Fun#toMethod(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return a {@link Method} instance that corresponds to the method reference. Please note, though, that the Method instance will *NOT* return the correct method name. Use Fun.getName for this purpose. + */ + static Method toMethod(Fun.With9ParamsAndVoid methodRef) { return SerializedLambdaToMethod.createMethodFromSuperConsumer(methodRef); } + + /** + * Ues this method to turn a Method Reference in the form of a double colon expression into a String holding the method name. That is to get 'isEmpty' from String::isEmpty. + *

+ * NB: An output a la 'lambda$16' can occur for corner cases, see Holger, on SO: "The limitations are that it will print not very useful method references for lambda expressions (references to the synthetic method containing the lambda code)" https://stackoverflow.com/a/21879031/6095334 + * TODO: In those cases where a string a la 'lambda$16' is returned, i.e. the method name could not be resolved, one could perhaps use Gunnar Morlings approach as a fallback? https://in.relation.to/2016/04/14/emulating-property-literals-with-java-8-method-references/ + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. A Method Reference, typically in the form using the double colon syntax, fx String::isEmpty + * @param A dummy generic value created to satisfy the compiler, which will otherwise get confused and be unable to choose the correct overloaded getName method + * @return the method name + */ + static String getName(Fun.With0ParamsAndVoidmethodRef) { return SerializedLambdaToMethod.createMethodNameFromSuperConsumer(methodRef); } + + /** + * @see Fun#getName(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return the method name + */ + static String getName(Fun.With1ParamAndVoidmethodRef) { return SerializedLambdaToMethod.createMethodNameFromSuperConsumer(methodRef); } + /** + * @see Fun#getName(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return the method name + */ + static String getName(Fun.With2ParamsAndVoidmethodRef) { return SerializedLambdaToMethod.createMethodNameFromSuperConsumer(methodRef); } + /** + * @see Fun#getName(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return the method name + */ + static String getName(Fun.With3ParamsAndVoidmethodRef) { return SerializedLambdaToMethod.createMethodNameFromSuperConsumer(methodRef); } + /** + * @see Fun#getName(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return the method name + */ + static String getName(Fun.With4ParamsAndVoidmethodRef) { return SerializedLambdaToMethod.createMethodNameFromSuperConsumer(methodRef); } + /** + * @see Fun#getName(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return the method name + */ + static String getName(Fun.With5ParamsAndVoidmethodRef) { return SerializedLambdaToMethod.createMethodNameFromSuperConsumer(methodRef); } + /** + * @see Fun#getName(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return the method name + */ + static String getName(Fun.With6ParamsAndVoidmethodRef) { return SerializedLambdaToMethod.createMethodNameFromSuperConsumer(methodRef); } + /** + * @see Fun#getName(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return the method name + */ + static String getName(Fun.With7ParamsAndVoidmethodRef) { return SerializedLambdaToMethod.createMethodNameFromSuperConsumer(methodRef); } + /** + * @see Fun#getName(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return the method name + */ + static String getName(Fun.With8ParamsAndVoidmethodRef) { return SerializedLambdaToMethod.createMethodNameFromSuperConsumer(methodRef); } + /** + * @see Fun#getName(With0ParamsAndVoid) + * + * @param methodRef a Method Reference, fx in the form of the double colon syntax like this 'MyClass::myAccessibleMethod', or 'myObject::myAccessibleMethod'. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @param When targeting an overloaded method you must help the compiler choose the correct overloaded toMethod method by specifying the parameters and return value in generics. + * @return the method name + */ + static String getName(Fun.With9ParamsAndVoid methodRef) { return SerializedLambdaToMethod.createMethodNameFromSuperConsumer(methodRef); } + + + //************************* NESTED STATIC INTERFACES FROM HERE ONWARDS. THE IDEA BEING TO CREATE A FLUENT API ****************************' + + @FunctionalInterface + interface With0Params extends Fun { + /** + * @return the return value/result of the invoked method + * @throws Exception if the invoked functions throws an Exception + */ + RETURN invoke() throws Exception; + + /** + * @return the return value/result of the invoked method + */ + @SneakyThrows + default RETURN invokeWithSneakyThrows(){ + return invoke(); + } + } + + /** + * Use the special *AndVoid subclasses for matching methods that return lower case void. + * Do note, though, that the *AndVoid interfaces will match any return type. + */ + @FunctionalInterface + interface With0ParamsAndVoid extends Fun { // A note on the DUMMY generic value: It was the only way to make the following jUnit assert pass: assertNotNull(Types2.[]>createMethod(getClass()::getDeclaredMethod)); See comment in DelegateTest + /** + * @throws Exception if the invoked functions throws an Exception + */ + void invoke() throws Exception; + + @SneakyThrows + default void invokeWithSneakyThrows(){ + invoke(); + } + } + + @FunctionalInterface + interface With1Param extends Fun { + /** + * @param param1 (not null) + * @return the return value/result of the invoked method + * @throws Exception if the invoked functions throws an Exception + */ + RETURN invoke(@NonNull @NotNull PARAM1 param1) throws Exception; + + /** + * @param param1 (not null) + * @return the return value/result of the invoked method + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default RETURN invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1){ + return invoke(param1); + } + } + + /** + * @see With0ParamsAndVoid + */ + @FunctionalInterface + interface With1ParamAndVoid extends Fun { + /** + * @param param1 (not null) + * @throws Exception if the invoked functions throws an Exception + */ + void invoke(@NonNull @NotNull PARAM1 param1) throws Exception; + + /** + * @param param1 (not null) + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default void invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1){ + invoke(param1); + } + } + + @FunctionalInterface + interface With2Params extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @return the return value/result of the invoked method + * @throws Exception if the invoked functions throws an Exception + */ + RETURN invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @return the return value/result of the invoked method + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default RETURN invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2){ + return invoke(param1, param2); + } + } + + /** + * @see With0ParamsAndVoid + */ + @FunctionalInterface + interface With2ParamsAndVoid extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @throws Exception if the invoked functions throws an Exception + */ + void invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default void invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2){ + invoke(param1, param2); + } + } + + @FunctionalInterface + interface With3Params extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @return the return value/result of the invoked method + * @throws Exception if the invoked functions throws an Exception + */ + RETURN invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @return the return value/result of the invoked method + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default RETURN invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3){ + return invoke(param1, param2, param3); + } + } + + /** + * @see With0ParamsAndVoid + */ + @FunctionalInterface + interface With3ParamsAndVoid extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @throws Exception if the invoked functions throws an Exception + */ + void invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default void invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3){ + invoke(param1, param2, param3); + } + } + + @FunctionalInterface + interface With4Params extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @return the return value/result of the invoked method + * @throws Exception if the invoked functions throws an Exception + */ + RETURN invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @return the return value/result of the invoked method + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default RETURN invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4){ + return invoke(param1, param2, param3, param4); + } + } + + /** + * @see With0ParamsAndVoid + */ + @FunctionalInterface + interface With4ParamsAndVoid extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @throws Exception if the invoked functions throws an Exception + */ + void invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default void invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4){ + invoke(param1, param2, param3, param4); + } + } + + @FunctionalInterface + interface With5Params extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @return the return value/result of the invoked method + * @throws Exception if the invoked functions throws an Exception + */ + RETURN invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @return the return value/result of the invoked method + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default RETURN invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5){ + return invoke(param1, param2, param3, param4, param5); + } + } + + /** + * @see With0ParamsAndVoid + */ + @FunctionalInterface + interface With5ParamsAndVoid extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @throws Exception if the invoked functions throws an Exception + */ + void invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default void invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5){ + invoke(param1, param2, param3, param4, param5); + } + } + + @FunctionalInterface + interface With6Params extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @return the return value/result of the invoked method + * @throws Exception if the invoked functions throws an Exception + */ + RETURN invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @return the return value/result of the invoked method + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default RETURN invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6){ + return invoke(param1, param2, param3, param4, param5, param6); + } + } + + /** + * @see With0ParamsAndVoid + */ + @FunctionalInterface + interface With6ParamsAndVoid extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @throws Exception if the invoked functions throws an Exception + */ + void invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default void invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6){ + invoke(param1, param2, param3, param4, param5, param6); + } + } + + @FunctionalInterface + interface With7Params extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @param param7 (not null) + * @return the return value/result of the invoked method + * @throws Exception if the invoked functions throws an Exception + */ + RETURN invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @param param7 (not null) + * @return the return value/result of the invoked method + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default RETURN invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7){ + return invoke(param1, param2, param3, param4, param5, param6, param7); + } + } + + /** + * @see With0ParamsAndVoid + */ + @FunctionalInterface + interface With7ParamsAndVoid extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @param param7 (not null) + * @throws Exception if the invoked functions throws an Exception + */ + void invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @param param7 (not null) + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default void invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7){ + invoke(param1, param2, param3, param4, param5, param6, param7); + } + } + + @FunctionalInterface + interface With8Params extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @param param7 (not null) + * @param param8 (not null) + * @return the return value/result of the invoked method + * @throws Exception if the invoked functions throws an Exception + */ + RETURN invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @param param7 (not null) + * @param param8 (not null) + * @return the return value/result of the invoked method + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default RETURN invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8){ + return invoke(param1, param2, param3, param4, param5, param6, param7, param8); + } + } + + /** + * @see With0ParamsAndVoid + */ + @FunctionalInterface + interface With8ParamsAndVoid extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @param param7 (not null) + * @param param8 (not null) + * @throws Exception if the invoked functions throws an Exception + */ + void invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @param param7 (not null) + * @param param8 (not null) + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default void invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8){ + invoke(param1, param2, param3, param4, param5, param6, param7, param8); + } + } + + @FunctionalInterface + interface With9Params extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @param param7 (not null) + * @param param8 (not null) + * @param param9 (not null) + * @return the return value/result of the invoked method + * @throws Exception if the invoked functions throws an Exception + */ + RETURN invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8, @NonNull @NotNull PARAM9 param9) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @param param7 (not null) + * @param param8 (not null) + * @param param9 (not null) + * @return the return value/result of the invoked method + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default RETURN invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8, @NonNull @NotNull PARAM9 param9){ + return invoke(param1, param2, param3, param4, param5, param6, param7, param8, param9); + } + } + + /** + * @see With0ParamsAndVoid + */ + @FunctionalInterface + interface With9ParamsAndVoid extends Fun { + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @param param7 (not null) + * @param param8 (not null) + * @param param9 (not null) + * @throws Exception if the invoked functions throws an Exception + */ + void invoke(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8, @NonNull @NotNull PARAM9 param9) throws Exception; + + /** + * @param param1 (not null) + * @param param2 (not null) + * @param param3 (not null) + * @param param4 (not null) + * @param param5 (not null) + * @param param6 (not null) + * @param param7 (not null) + * @param param8 (not null) + * @param param9 (not null) + * @throws NullPointerException if one or more of the arguments are null + */ + @SneakyThrows + default void invokeWithSneakyThrows(@NonNull @NotNull PARAM1 param1, @NonNull @NotNull PARAM2 param2, @NonNull @NotNull PARAM3 param3, @NonNull @NotNull PARAM4 param4, @NonNull @NotNull PARAM5 param5, @NonNull @NotNull PARAM6 param6, @NonNull @NotNull PARAM7 param7, @NonNull @NotNull PARAM8 param8, @NonNull @NotNull PARAM9 param9){ + invoke(param1, param2, param3, param4, param5, param6, param7, param8, param9); + } + } + +} diff --git a/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/FunctionInvocationResult.java b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/FunctionInvocationResult.java new file mode 100644 index 000000000..171b66d60 --- /dev/null +++ b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/FunctionInvocationResult.java @@ -0,0 +1,39 @@ +package fr.insee.vtl.engine.utils.safetymirror; + +import lombok.Builder; +import lombok.Data; + +import java.lang.reflect.Method; + +/** + * Copyright 2016 Anders Granau Høfft + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * END OF NOTICE + * + * @author Anders Granau Høfft + */ +@Builder +@Data +public class FunctionInvocationResult { + + Method method; + Object[] arguments; + RESULT result; + Exception exception; + + public boolean exceptionThrown(){ + return exception!=null; + } + +} diff --git a/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/util/SerializedLambdaToMethod.java b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/util/SerializedLambdaToMethod.java new file mode 100644 index 000000000..9a7086a85 --- /dev/null +++ b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/util/SerializedLambdaToMethod.java @@ -0,0 +1,116 @@ +package com.github.hervian.reflection.util; + +import fr.insee.vtl.engine.utils.safetymirror.Fun; + +import java.lang.invoke.SerializedLambda; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Copyright 2016 Anders Granau Høfft + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * END OF NOTICE + * + * @author Anders Granau Høfft + * + * Thanks to Holger for this StackOverflow answer: https://stackoverflow.com/a/21879031/6095334 + */ +public class SerializedLambdaToMethod { + + private SerializedLambdaToMethod(){} + + public static Method createMethodFromSuperConsumer(Fun lambda) { + SerializedLambda serializedLambda = getSerializedLambda(lambda); + return getMethod(serializedLambda); + } + + private static Method getMethod(SerializedLambda serializedLambda) { + if (serializedLambda==null) { + return null; + } else { + String className = SignatureUtil.compactClassName(serializedLambda.getImplClass(), false); + try { + return Class.forName(className).getDeclaredMethod(serializedLambda.getImplMethodName(), getParameters(serializedLambda.getImplMethodSignature())); + } catch (NoSuchMethodException | SecurityException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + } + + private static SerializedLambda getSerializedLambda(Fun lambda) { + SerializedLambda serializedLambda = null; + for (Class cl = lambda.getClass(); cl != null; cl = cl.getSuperclass()) { + try { + Method m = cl.getDeclaredMethod("writeReplace"); + m.setAccessible(true); + Object replacement = m.invoke(lambda); + if (!(replacement instanceof SerializedLambda)) + break;// custom interface implementation + serializedLambda = (SerializedLambda) replacement; + break; + } catch (NoSuchMethodException e) { + } catch (IllegalAccessException | InvocationTargetException | SecurityException e) { + throw new RuntimeException(e); + } + } + return serializedLambda; + } + + public static String createMethodNameFromSuperConsumer(Fun lambda) { + SerializedLambda serializedLambda = getSerializedLambda(lambda); + return serializedLambda.getImplMethodName(); + } + + private static Class[] getParameters(String signature) throws ClassNotFoundException { + String[] parameters = signature.substring(1, signature.lastIndexOf(')')).replaceAll("/", ".").split(";"); + String[] params = SignatureUtil.methodSignatureArgumentTypes(signature, false); + + Class[] paramTypes = new Class[params.length]; + for (int i=0; i getPrimitiveClass(String param) { + switch (param){ + case "byte" : return byte.class; + case "short" : return short.class; + case "int" : return int.class; + case "long" : return long.class; + case "double" : return double.class; + case "float" : return float.class; + case "boolean" : return boolean.class; + case "char" : return char.class; + default: throw new UnsupportedOperationException("Unmapped switch case. Have a new primitive data type been added to the Java language?"); + } + } + +} diff --git a/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/util/SignatureUtil.java b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/util/SignatureUtil.java new file mode 100644 index 000000000..3c14c9d1a --- /dev/null +++ b/vtl-engine/src/main/java/fr/insee/vtl/engine/utils/safetymirror/util/SignatureUtil.java @@ -0,0 +1,207 @@ +package com.github.hervian.reflection.util; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * Copyright 2000-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Modifications copyright (C) 2018 com.github.hervian (Copy pastet parts of file from: http://www.javased.com/index.php?source_dir=jmd/src/org/apache/bcel/classfile/Utility.java) + * @author Anders Granau Høfft + * + */ +public class SignatureUtil { + + private static int unwrap( ThreadLocal tl ) { + return ((Integer) tl.get()).intValue(); + } + + + private static void wrap( ThreadLocal tl, int value ) { + tl.set(value); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static ThreadLocal consumed_chars = new ThreadLocal() { + + protected Integer initialValue() { + return 0; + } + }; + + /** + * @param signature Method signature + * @param chopit Shorten class names ? + * @return Array of argument types + * @throws RuntimeException + */ + public static final String[] methodSignatureArgumentTypes( String signature, boolean chopit ) throws RuntimeException { + List vec = new ArrayList<>(); + int index; + try { // Read all declarations between for `(' and `)' + if (signature.charAt(0) != '(') { + throw new RuntimeException("Invalid method signature: " + signature); + } + index = 1; // current string position + while (signature.charAt(index) != ')') { + vec.add(signatureToString(signature.substring(index), chopit)); + //corrected concurrent private static field acess + index += unwrap(consumed_chars); // update position + } + } catch (StringIndexOutOfBoundsException e) { // Should never occur + throw new RuntimeException("Invalid method signature: " + signature); + } + return (String[]) vec.toArray(new String[vec.size()]); + } + + /** + * The field signature represents the value of an argument to a function or + * the value of a variable. It is a series of bytes generated by the + * following grammar: + * + *
 
+     *  ::=  
+     *       ::= || 
+     *        ::= B|C|D|F|I|J|S|Z 
+     *      ::= L; 
+     *       ::= [ 
+     * 
+     * The meaning of the base types is as follows: 
+     * B byte signed byte 
+     * C char character 
+     * D double double precision IEEE float 
+     * F float single precision IEEE float 
+     * I int integer 
+     * J long long integer 
+     * L; ... an object of the given class 
+     * S short signed short 
+     * Z boolean true or false 
+     * [ ... array 
+     * 
+ * + * This method converts this string into a Java type declaration such as + * `String[]' and throws a `RuntimeException' when the parsed type is + * invalid. + * + * @param signature Class signature + * @param chopit Flag that determines whether chopping is executed or not + * @return Java type declaration + * @throws RuntimeException + */ + public static final String signatureToString( String signature, boolean chopit ) { + //corrected concurrent private static field acess + wrap(consumed_chars, 1); // This is the default, read just one char like `B' + try { + switch (signature.charAt(0)) { + case 'B': + return "byte"; + case 'C': + return "char"; + case 'D': + return "double"; + case 'F': + return "float"; + case 'I': + return "int"; + case 'J': + return "long"; + case 'L': { // Full class name + int index = signature.indexOf(';'); // Look for closing `;' + if (index < 0) { + throw new RuntimeException("Invalid signature: " + signature); + } + //corrected concurrent private static field acess + wrap(consumed_chars, index + 1); // "Lblabla;" `L' and `;' are removed + return compactClassName(signature.substring(1, index), chopit); + } + case 'S': + return "short"; + case 'Z': + return "boolean"; + case '[': { // Array declaration + int n; + StringBuffer brackets; + String type; + int consumed_chars; // Shadows global var + brackets = new StringBuffer(); // Accumulate []'s + // Count opening brackets and look for optional size argument + for (n = 0; signature.charAt(n) == '['; n++) { + brackets.append("[]"); + } + consumed_chars = n; // Remember value + // The rest of the string denotes a `' + type = signatureToString(signature.substring(n), chopit); + //corrected concurrent private static field acess + //Utility.consumed_chars += consumed_chars; is replaced by: + int _temp = unwrap(SignatureUtil.consumed_chars) + consumed_chars; + wrap(SignatureUtil.consumed_chars, _temp); + return type + brackets.toString(); + } + case 'V': + return "void"; + default: + throw new RuntimeException("Invalid signature: `" + signature + "'"); + } + } catch (StringIndexOutOfBoundsException e) { // Should never occur + throw new RuntimeException("Invalid signature: " + e + ":" + signature); + } + } + + public static final String compactClassName( String str ) { + return compactClassName(str, true); + } + + + /** + * Shorten long class name str, i.e., chop off the prefix, + * if the + * class name starts with this string and the flag chopit is true. + * Slashes / are converted to dots .. + * + * @param str The long class name + * @param prefix The prefix the get rid off + * @param chopit Flag that determines whether chopping is executed or not + * @return Compacted class name + */ + public static final String compactClassName( String str, String prefix, boolean chopit ) { + int len = prefix.length(); + str = str.replace('/', '.'); // Is `/' on all systems, even DOS + if (chopit) { + // If string starts with `prefix' and contains no further dots + if (str.startsWith(prefix) && (str.substring(len).indexOf('.') == -1)) { + str = str.substring(len); + } + } + return str; + } + + + /** + * Shorten long class names, java/lang/String becomes + * java.lang.String, + * e.g.. If chopit is true the prefix java.lang + * is also removed. + * + * @param str The long class name + * @param chopit Flag that determines whether chopping is executed or not + * @return Compacted class name + */ + public static final String compactClassName( String str, boolean chopit ) { + return compactClassName(str, "java.lang.", chopit); + } + + +} diff --git a/vtl-engine/src/test/java/fr/insee/vtl/engine/VtlScriptEngineTest.java b/vtl-engine/src/test/java/fr/insee/vtl/engine/VtlScriptEngineTest.java index 5dbf0dee9..adebd03d7 100644 --- a/vtl-engine/src/test/java/fr/insee/vtl/engine/VtlScriptEngineTest.java +++ b/vtl-engine/src/test/java/fr/insee/vtl/engine/VtlScriptEngineTest.java @@ -1,6 +1,6 @@ package fr.insee.vtl.engine; -import com.github.hervian.reflection.Fun; +import fr.insee.vtl.engine.utils.safetymirror.Fun; import fr.insee.vtl.engine.exceptions.FunctionNotFoundException; import fr.insee.vtl.engine.exceptions.UndefinedVariableException; import fr.insee.vtl.engine.exceptions.VtlSyntaxException;