[Git][java-team/invokebinder][upstream] New upstream version 1.12
Jérôme Charaoui (@lavamind)
gitlab at salsa.debian.org
Thu Oct 27 00:53:06 BST 2022
Jérôme Charaoui pushed to branch upstream at Debian Java Maintainers / invokebinder
Commits:
11486fa1 by Jérôme Charaoui at 2022-10-25T19:37:49-04:00
New upstream version 1.12
- - - - -
24 changed files:
- .travis.yml
- pom.xml
- src/main/java/com/headius/invokebinder/Binder.java
- src/main/java/com/headius/invokebinder/Signature.java
- src/main/java/com/headius/invokebinder/SmartBinder.java
- + src/main/java/com/headius/invokebinder/Util.java
- src/main/java/com/headius/invokebinder/transform/Cast.java
- src/main/java/com/headius/invokebinder/transform/Catch.java
- src/main/java/com/headius/invokebinder/transform/Collect.java
- src/main/java/com/headius/invokebinder/transform/Convert.java
- src/main/java/com/headius/invokebinder/transform/Drop.java
- src/main/java/com/headius/invokebinder/transform/Filter.java
- src/main/java/com/headius/invokebinder/transform/FilterReturn.java
- src/main/java/com/headius/invokebinder/transform/Fold.java
- src/main/java/com/headius/invokebinder/transform/Insert.java
- src/main/java/com/headius/invokebinder/transform/Permute.java
- src/main/java/com/headius/invokebinder/transform/Spread.java
- src/main/java/com/headius/invokebinder/transform/Transform.java
- src/main/java/com/headius/invokebinder/transform/TryFinally.java
- src/main/java/com/headius/invokebinder/transform/Varargs.java
- + src/main/java/module-info.java
- src/test/java/com/headius/invokebinder/BinderTest.java
- src/test/java/com/headius/invokebinder/Subjects.java
- + src/test/java/com/headius/invokebinder/ToJavaTest.java
Changes:
=====================================
.travis.yml
=====================================
@@ -2,12 +2,8 @@ language: java
matrix:
include:
- os: linux
- jdk: oraclejdk8
+ arch: amd64
+ jdk: openjdk11
- os: linux
- services:
- - docker
- before_install:
- - docker pull ibmcom/ibmjava:8-sdk
- script:
- - docker run -v `pwd`:/work ibmcom/ibmjava:8-sdk /bin/sh -c "cd work; java -version; ./mvnw clean test"
-
+ arch: ppc64le
+ jdk: openjdk11
=====================================
pom.xml
=====================================
@@ -3,7 +3,7 @@
<groupId>com.headius</groupId>
<artifactId>invokebinder</artifactId>
<packaging>bundle</packaging>
- <version>1.8-SNAPSHOT</version>
+ <version>1.12</version>
<name>invokebinder</name>
<url>http://maven.apache.org</url>
@@ -51,15 +51,44 @@
<Export-Package>com.headius.invokebinder.*</Export-Package>
</instructions>
</configuration>
+ <!-- https://issues.apache.org/jira/browse/FELIX-5698 -->
+ <dependencies>
+ <dependency>
+ <groupId>biz.aQute.bnd</groupId>
+ <artifactId>biz.aQute.bndlib</artifactId>
+ <version>5.2.0</version>
+ </dependency>
+ </dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
- <version>2.0.2</version>
+ <version>3.7.0</version>
+ <executions>
+ <execution>
+ <id>default-compile</id>
+ <configuration>
+ <includes>
+ <include>module-info.java</include>
+ </includes>
+ <release>9</release>
+ </configuration>
+ </execution>
+ <execution>
+ <id>base-compile</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <excludes>
+ <exclude>module-info.java</exclude>
+ </excludes>
+ </configuration>
+ </execution>
+ </executions>
<configuration>
<source>1.7</source>
<target>1.7</target>
- <encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
@@ -70,6 +99,13 @@
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>3.2.0</version>
+ <configuration>
+ <source>8</source>
+ </configuration>
+ </plugin>
</plugins>
</build>
@@ -77,7 +113,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
- <version>4.9</version>
+ <version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>
=====================================
src/main/java/com/headius/invokebinder/Binder.java
=====================================
@@ -34,9 +34,10 @@ import java.io.PrintStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.lang.invoke.VarHandle;
import java.lang.reflect.Method;
-import java.util.ArrayList;
import java.util.Arrays;
+import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.logging.Logger;
@@ -68,8 +69,8 @@ import java.util.logging.Logger;
public class Binder {
private final Logger logger = Logger.getLogger("Invoke Binder");
- private final List<Transform> transforms = new ArrayList<>();
- private final List<MethodType> types = new ArrayList<>();
+ private final List<Transform> transforms = new LinkedList<>();
+ private final List<MethodType> types = new LinkedList<>();
private final MethodType start;
private final MethodHandles.Lookup lookup;
@@ -879,6 +880,18 @@ public class Binder {
return new Binder(this, new Collect(type(), index, type));
}
+ /**
+ * Box all incoming arguments from the given position onward into the given array type.
+ *
+ * @param index the index from which to start boxing args
+ * @param type the array type into which the args will be boxed
+ * @param collector a function to use for collecting the arguments
+ * @return a new Binder
+ */
+ public Binder collect(int index, Class<?> type, MethodHandle collector) {
+ return new Binder(this, new Collect(type(), index, type, collector));
+ }
+
/**
* Box a range of incoming arguments into the given array type.
*
@@ -891,6 +904,22 @@ public class Binder {
return new Binder(this, new Collect(type(), index, count, type));
}
+ /**
+ * Box a range of incoming arguments into the given array type using the given constructor to construct the array.
+ *
+ * The collector signature should match (T1, ..., Tn) where T is the type of the arguments being collected and n
+ * is the number of arguments being collected.
+ *
+ * @param index the index from which to start boxing args
+ * @param count the count of arguments to box
+ * @param type the array type into which the args will be boxed
+ * @param collector a function to use for collecting the arguments
+ * @return a new Binder
+ */
+ public Binder collect(int index, int count, Class<?> type, MethodHandle collector) {
+ return new Binder(this, new Collect(type(), index, count, type, collector));
+ }
+
/**
* Box all incoming arguments from the given position onward into the given array type.
* This version accepts a variable number of incoming arguments.
@@ -927,6 +956,14 @@ public class Binder {
return new Binder(this, new Fold(function));
}
+ /**
+ * Process the incoming arguments using the given handle, leaving the argument list
+ * unmodified.
+ *
+ * @param function the function that will process the incoming arguments. Its
+ * signature must match the current signature's arguments exactly.
+ * @return a new Binder
+ */
public Binder foldVoid(MethodHandle function) {
if (type().returnType() == void.class) {
return fold(function);
@@ -984,8 +1021,12 @@ public class Binder {
}
/**
- * Filter incoming arguments, starting at the given index, replacing each with the
- * result of calling the associated function in the given list.
+ * Filter incoming arguments, from the given index, replacing each with the
+ * result of calling the associated function in the given list. Note that
+ * the order in which the filters are applied is undefined; OpenJDK produces
+ * handles that execute them in reverse order.
+ *
+ * @see #filterForward(int, MethodHandle...)
*
* @param index the index of the first argument to filter
* @param functions the array of functions to transform the arguments
@@ -995,6 +1036,26 @@ public class Binder {
return new Binder(this, new Filter(index, functions));
}
+ /**
+ * Filter incoming arguments, from the given index, replacing each with the
+ * result of calling the associated function in the given list. This version
+ * guarantees left-to-right evaluation of filter functions, potentially at
+ * the cost of a more complex handle tree.
+ *
+ * @param index the index of the first argument to filter
+ * @param functions the array of functions to transform the arguments
+ * @return a new Binder
+ */
+ public Binder filterForward(int index, MethodHandle... functions) {
+ Binder filtered = this;
+
+ for (int i = 0; i < functions.length; i++) {
+ filtered = filtered.filter(index + i, functions[i]);
+ }
+
+ return filtered;
+ }
+
/**
* Filter return value, using a function that produces the current return type
* from another type. The new endpoint will have the return value that the
@@ -1524,6 +1585,36 @@ public class Binder {
return invoke(MethodHandles.arrayElementSetter(type().parameterType(0)));
}
+ /**
+ * Apply the chain of transforms and bind them to a volatile array element set.
+ *
+ * @see Binder#arraySet()
+ * @see VarHandle#setVolatile(Object...)
+ */
+ public MethodHandle arraySetVolatile() {
+ return arrayAccess(VarHandle.AccessMode.SET_VOLATILE);
+ }
+
+ /**
+ * Apply the chain of transforms and bind them to a release-fenced array element set.
+ *
+ * @see Binder#arraySet()
+ * @see VarHandle#setRelease(Object...)
+ */
+ public MethodHandle arraySetAcquire() {
+ return arrayAccess(VarHandle.AccessMode.SET_RELEASE);
+ }
+
+ /**
+ * Apply the chain of transforms and bind them to an opaque (no ordering guarantee) array element set.
+ *
+ * @see Binder#arraySet()
+ * @see VarHandle#setVolatile(Object...)
+ */
+ public MethodHandle arraySetOpaque() {
+ return arrayAccess(VarHandle.AccessMode.SET_OPAQUE);
+ }
+
/**
* Apply the chain of transforms and bind them to an array element get. The signature
@@ -1536,6 +1627,44 @@ public class Binder {
return invoke(MethodHandles.arrayElementGetter(type().parameterType(0)));
}
+ /**
+ * Apply the chain of transforms and bind them to a volatile array element get.
+ *
+ * @see Binder#arrayGet()
+ * @see VarHandle#getVolatile(Object...)
+ */
+ public MethodHandle arrayGetVolatile() {
+ return arrayAccess(VarHandle.AccessMode.GET_VOLATILE);
+ }
+
+ /**
+ * Apply the chain of transforms and bind them to an acquire-fenced array element get.
+ *
+ * @see Binder#arrayGet()
+ * @see VarHandle#getAcquire(Object...)
+ */
+ public MethodHandle arrayGetAcquire() {
+ return arrayAccess(VarHandle.AccessMode.GET_ACQUIRE);
+ }
+
+ /**
+ * Apply the chain of transforms and bind them to an opaque (no ordering guarantee) array element get.
+ *
+ * @see Binder#arrayGet()
+ * @see VarHandle#getVolatile(Object...)
+ */
+ public MethodHandle arrayGetOpaque() {
+ return arrayAccess(VarHandle.AccessMode.GET_OPAQUE);
+ }
+
+ /**
+ * Apply the chain of transforms and bind them to an array varhandle operation. The
+ * signature at the endpoint must match the VarHandle access type passed in.
+ */
+ public MethodHandle arrayAccess(VarHandle.AccessMode mode) {
+ return invoke(MethodHandles.arrayElementVarHandle(type().parameterType(0)).toMethodHandle(mode));
+ }
+
/**
* Apply the chain of transforms and bind them to a boolean branch as from
* java.lang.invoke.MethodHandles.guardWithTest. As with GWT, the current endpoint
@@ -1560,4 +1689,20 @@ public class Binder {
return invoke(MethodHandles.invoker(start));
}
+ /**
+ * Produce Java code that would perform equivalent operations to this binder.
+ *
+ * @return Java code for the handle adaptations this Binder would produce.
+ */
+ public String toJava(MethodType incoming) {
+ StringBuilder builder = new StringBuilder();
+ boolean second = false;
+ for (Transform transform : transforms) {
+ if (second) builder.append('\n');
+ second = true;
+ builder.append(transform.toJava(incoming));
+ }
+ return builder.toString();
+ }
+
}
=====================================
src/main/java/com/headius/invokebinder/Signature.java
=====================================
@@ -788,4 +788,22 @@ public class Signature {
return offsets;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Signature signature = (Signature) o;
+
+ if (!methodType.equals(signature.methodType)) return false;
+
+ return Arrays.equals(argNames, signature.argNames);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = methodType.hashCode();
+ result = 31 * result + Arrays.hashCode(argNames);
+ return result;
+ }
}
=====================================
src/main/java/com/headius/invokebinder/SmartBinder.java
=====================================
@@ -853,6 +853,30 @@ public class SmartBinder {
return new SmartBinder(this, newSignature, binder.collect(index, signature().argCount() - (newSignature.argCount() - 1), Array.newInstance(signature().argType(index), 0).getClass()));
}
+ /**
+ * Collect arguments matching namePattern into an trailing array argument
+ * named outName, using collector to construct the array object.
+ *
+ * The collector signature should match (T1, ..., Tn) where T is the type of the arguments being collected and n
+ * is the number of arguments being collected.
+ *
+ * The namePattern is a standard regular expression.
+ *
+ * @param outName the name of the new array argument
+ * @param namePattern a pattern with which to match arguments for collecting
+ * @param collector a function to use for collecting the arguments
+ * @return a new SmartBinder with the collect applied
+ */
+ public SmartBinder collect(String outName, String namePattern, MethodHandle collector) {
+ int index = signature().argOffsets(namePattern);
+
+ assert index >= 0 : "no arguments matching " + namePattern + " found in signature " + signature();
+
+ Signature newSignature = signature().collect(outName, namePattern);
+
+ return new SmartBinder(this, newSignature, binder.collect(index, signature().argCount() - (newSignature.argCount() - 1), Array.newInstance(signature().argType(index), 0).getClass(), collector));
+ }
+
///////////////////////////////////////////////////////////////////////////
// CASTS, based on MethodHandles.explicitCastArguments and MethodHandle.asType.
///////////////////////////////////////////////////////////////////////////
@@ -1165,4 +1189,11 @@ public class SmartBinder {
return new SmartBinder(newSig, newBinder);
}
+
+ /**
+ * @see Binder#tryFinally(MethodHandle)
+ */
+ public SmartBinder tryFinally(MethodHandle post) {
+ return new SmartBinder(this, signature(), binder.tryFinally(post));
+ }
}
=====================================
src/main/java/com/headius/invokebinder/Util.java
=====================================
@@ -0,0 +1,23 @@
+package com.headius.invokebinder;
+
+/**
+ * Utilities used by InvokeBinder classes.
+ */
+public class Util {
+ public static boolean IS_JAVA9;
+
+ static {
+ boolean isJava9;
+ try {
+ Class.forName("java.lang.Module");
+ isJava9 = true;
+ } catch (Exception e) {
+ isJava9 = false;
+ }
+ IS_JAVA9 = isJava9;
+ }
+
+ public static boolean isJava9() {
+ return IS_JAVA9;
+ }
+}
=====================================
src/main/java/com/headius/invokebinder/transform/Cast.java
=====================================
@@ -54,4 +54,12 @@ public class Cast extends Transform {
public String toString() {
return "cast args to " + type;
}
+
+ public String toJava(MethodType incoming) {
+ StringBuilder builder = new StringBuilder("handle = MethodHandles.explicitCastArguments(handle, ");
+ buildClassArguments(builder, type.parameterArray());
+ builder.append(");");
+ return builder.toString();
+ }
+
}
=====================================
src/main/java/com/headius/invokebinder/transform/Catch.java
=====================================
@@ -26,6 +26,7 @@ import java.lang.invoke.MethodType;
*/
public class Catch extends Transform {
+ public static final String EXCEPTION_HANDLER_JAVA = "<exception handler>";
private final Class<? extends Throwable> throwable;
private final MethodHandle function;
@@ -45,4 +46,11 @@ public class Catch extends Transform {
public String toString() {
return "catch exception type " + throwable + " using " + function;
}
+
+ public String toJava(MethodType incoming) {
+ StringBuilder builder = new StringBuilder("handle = MethodHandles.catchException(handle, ");
+ buildClassArgument(builder, throwable);
+ builder.append(", ").append(EXCEPTION_HANDLER_JAVA).append(");");
+ return builder.toString();
+ }
}
=====================================
src/main/java/com/headius/invokebinder/transform/Collect.java
=====================================
@@ -18,12 +18,13 @@ package com.headius.invokebinder.transform;
import com.headius.invokebinder.Binder;
import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
/**
* An argument-boxing transform with a fixed incoming size.
*
- * Equivalent call: MethodHandle.asCollector(Class, int)
+ * Equivalent call: MethodHandle.asCollector(Class, int) or MethodHandles.collectArguments
*/
public class Collect extends Transform {
@@ -31,12 +32,22 @@ public class Collect extends Transform {
private final int index;
private final int count;
private final Class<?> arrayType;
+ private final MethodHandle collector;
public Collect(MethodType source, int index, Class<?> arrayType) {
this.source = source;
this.index = index;
this.count = source.parameterCount() - index;
this.arrayType = arrayType;
+ this.collector = null;
+ }
+
+ public Collect(MethodType source, int index, Class<?> arrayType, MethodHandle collector) {
+ this.source = source;
+ this.index = index;
+ this.count = source.parameterCount() - index;
+ this.arrayType = arrayType;
+ this.collector = collector;
}
public Collect(MethodType source, int index, int count, Class<?> arrayType) {
@@ -44,38 +55,40 @@ public class Collect extends Transform {
this.index = index;
this.count = count;
this.arrayType = arrayType;
+ this.collector = null;
+ }
+
+ public Collect(MethodType source, int index, int count, Class<?> arrayType, MethodHandle collector) {
+ this.source = source;
+ this.index = index;
+ this.count = count;
+ this.arrayType = arrayType;
+ this.collector = collector;
}
public MethodHandle up(MethodHandle target) {
- if (index + count == source.parameterCount()) {
+ if (onlyTail()) {
// fast path for tail args
- return target.asCollector(arrayType, count);
- } else {
- int[] movePermute = new int[source.parameterCount()];
- int[] moveBackPermute = new int[target.type().parameterCount()];
- // pre
- for (int i = 0; i < index; i++) {
- movePermute[i] = i;
- moveBackPermute[i] = i;
+ if (collector == null) {
+ return target.asCollector(arrayType, count);
}
- // post
- int shifted = 0;
- for (int i = index; i + count < movePermute.length; i++, shifted++) movePermute[i] = i + count;
- for (int i = index; i + 1 < moveBackPermute.length; i++) moveBackPermute[i + 1] = i;
-
- // collected args
- for (int i = index + shifted; i < movePermute.length; i++) movePermute[i] = i - shifted;
- moveBackPermute[index] = moveBackPermute.length - 1;
+ return MethodHandles.collectArguments(target, index, collector);
+ } else {
+ Permutes permutes = buildPermutes(source, target.type());
- return Binder.from(source)
- .permute(movePermute)
- .collect(source.parameterCount() - count, arrayType)
- .permute(moveBackPermute)
- .invoke(target);
+ Binder binder = preparePermuteBinder(permutes);
+ return binder.invoke(target);
}
}
+ private Binder preparePermuteBinder(Permutes permutes) {
+ return Binder.from(source)
+ .permute(permutes.movePermute)
+ .collect(source.parameterCount() - count, arrayType, collector)
+ .permute(permutes.moveBackPermute);
+ }
+
public MethodType down(MethodType type) {
assertTypesAreCompatible();
@@ -96,4 +109,67 @@ public class Collect extends Transform {
public String toString() {
return "collect at " + index + " into " + arrayType.getName();
}
+
+ public String toJava(MethodType incoming) {
+ StringBuilder builder = new StringBuilder();
+ if (onlyTail()) {
+ if (collector == null) {
+ builder.append("handle = handle.asCollector(");
+ buildClassArgument(builder, arrayType);
+ builder
+ .append(", ")
+ .append(count)
+ .append(");");
+ } else {
+ builder.append("handle = MethodHandles.collectArguments(");
+
+ builder
+ .append("handle, ")
+ .append(count)
+ .append(", ");
+
+ buildClassArgument(builder, arrayType);
+
+ builder.append(");");
+ }
+ } else {
+ Permutes permutes = buildPermutes(source, incoming);
+
+ Binder binder = preparePermuteBinder(permutes);
+ return binder.toJava(incoming);
+ }
+ return builder.toString();
+ }
+
+ private boolean onlyTail() {
+ return index + count == source.parameterCount();
+ }
+
+ private static class Permutes {
+ private final int[] movePermute;
+ private final int[] moveBackPermute;
+
+ private Permutes(MethodType source, MethodType target, int index, int count) {
+ movePermute = new int[source.parameterCount()];
+ moveBackPermute = new int[target.parameterCount()];
+ // pre
+ for (int i = 0; i < index; i++) {
+ movePermute[i] = i;
+ moveBackPermute[i] = i;
+ }
+
+ // post
+ int shifted = 0;
+ for (int i = index; i + count < movePermute.length; i++, shifted++) movePermute[i] = i + count;
+ for (int i = index; i + 1 < moveBackPermute.length; i++) moveBackPermute[i + 1] = i;
+
+ // collected args
+ for (int i = index + shifted; i < movePermute.length; i++) movePermute[i] = i - shifted;
+ moveBackPermute[index] = moveBackPermute.length - 1;
+ }
+ }
+
+ private Permutes buildPermutes(MethodType source, MethodType target) {
+ return new Permutes(source, target, index, count);
+ }
}
=====================================
src/main/java/com/headius/invokebinder/transform/Convert.java
=====================================
@@ -53,4 +53,14 @@ public class Convert extends Transform {
public String toString() {
return "convert args to " + type;
}
+
+ public String toJava(MethodType incoming) {
+ String methodTypeJava = generateMethodType(type);
+
+ if (incoming.returnType() == void.class) {
+ return "handle = MethodHandles.explicitCastArguments(handle.asType(" + methodTypeJava + ", " + methodTypeJava + ");";
+ }
+
+ return "handle = handle.asType(" + methodTypeJava + ");";
+ }
}
=====================================
src/main/java/com/headius/invokebinder/transform/Drop.java
=====================================
@@ -46,4 +46,14 @@ public class Drop extends Transform {
public String toString() {
return "drop " + Arrays.toString(types) + " at " + position;
}
+
+ public String toJava(MethodType incoming) {
+ StringBuilder builder = new StringBuilder("handle = MethodHandles.dropArguments(handle, ");
+
+ builder.append(position).append(", ");
+ buildClassArguments(builder, types);
+ builder.append(");");
+
+ return builder.toString();
+ }
}
=====================================
src/main/java/com/headius/invokebinder/transform/Filter.java
=====================================
@@ -26,10 +26,11 @@ import java.util.Arrays;
* Equivalent call: MethodHandles.filterArguments(MethodHandle, int, MethodHandle...).
*/
public class Filter extends Transform {
-
private final int index;
private final MethodHandle[] functions;
+ public static final String FILTER_FUNCTIONS_JAVA = "<filter functions>";
+
public Filter(int index, MethodHandle... functions) {
this.index = index;
this.functions = functions;
@@ -49,4 +50,8 @@ public class Filter extends Transform {
public String toString() {
return "fold args from " + index + " with " + Arrays.toString(functions);
}
+
+ public String toJava(MethodType incoming) {
+ return "handle = MethodHandles.filterArguments(handle, " + index + ", " + FILTER_FUNCTIONS_JAVA + ");";
+ }
}
=====================================
src/main/java/com/headius/invokebinder/transform/FilterReturn.java
=====================================
@@ -27,9 +27,10 @@ import java.lang.invoke.MethodType;
* Equivalent call: MethodHandles.filterReturn(MethodHandle, MethodHandle).
*/
public class FilterReturn extends Transform {
-
private final MethodHandle function;
+ public static final String FILTER_FUNCTION_JAVA = "<filter function>";
+
public FilterReturn(MethodHandle function) {
this.function = function;
}
@@ -53,4 +54,8 @@ public class FilterReturn extends Transform {
public String toString() {
return "filter return with " + function;
}
+
+ public String toJava(MethodType incoming) {
+ return "handle = MethodHandles.filterReturnValue(handle, " + FILTER_FUNCTION_JAVA + ");";
+ }
}
=====================================
src/main/java/com/headius/invokebinder/transform/Fold.java
=====================================
@@ -25,9 +25,10 @@ import java.lang.invoke.MethodType;
* Equivalent call: MethodHandles.foldArguments(MethodHandle, MethodHandle).
*/
public class Fold extends Transform {
-
private final MethodHandle function;
+ public static final String FOLD_FUNCTION_JAVA = "<fold function>";
+
public Fold(MethodHandle function) {
this.function = function;
}
@@ -44,4 +45,8 @@ public class Fold extends Transform {
public String toString() {
return "fold args with " + function;
}
+
+ public String toJava(MethodType incoming) {
+ return "handle = MethodHandles.foldArguments(handle, " + FOLD_FUNCTION_JAVA + ");";
+ }
}
=====================================
src/main/java/com/headius/invokebinder/transform/Insert.java
=====================================
@@ -107,6 +107,30 @@ public class Insert extends Transform {
return "insert " + Arrays.toString(types()) + " at " + position;
}
+ public String toJava(MethodType incoming) {
+ StringBuilder builder = new StringBuilder("handle = MethodHandles.insertArguments(handle, ");
+ builder
+ .append(position)
+ .append(", ");
+
+ // we cast all arguments since natural type will frequently be wrong
+ boolean second = false;
+ for (int i = 0; i < types.length; i++) {
+ if (second) builder.append(", ");
+ second = true;
+
+ buildClassCast(builder, types[i]);
+ if (types[i].isPrimitive()) {
+ buildPrimitiveJava(builder, values[i]);
+ } else {
+ builder.append("value").append(i + 1);
+ }
+ }
+ builder.append(");");
+
+ return builder.toString();
+ }
+
private Class<?>[] types() {
Class<?>[] types = new Class<?>[values.length];
for (int i = 0; i < types.length; i++) {
=====================================
src/main/java/com/headius/invokebinder/transform/Permute.java
=====================================
@@ -57,4 +57,16 @@ public class Permute extends Transform {
public String toString() {
return "permute " + source + " with " + Arrays.toString(reorder);
}
+
+ public String toJava(MethodType incoming) {
+ StringBuilder builder = new StringBuilder("handle = MethodHandles.permuteArguments(handle, ");
+
+ String reorder = Arrays.toString(this.reorder);
+ reorder = reorder.substring(1, reorder.length() - 1);
+
+ builder.append(generateMethodType(source) + ", new int[] {" + reorder + "});");
+
+ return builder.toString();
+ }
+
}
=====================================
src/main/java/com/headius/invokebinder/transform/Spread.java
=====================================
@@ -52,4 +52,17 @@ public class Spread extends Transform {
public String toString() {
return "spread " + source + " to " + down(source);
}
+
+ public String toJava(MethodType incoming) {
+ StringBuilder builder = new StringBuilder("handle = handle.asSpreader(");
+
+ buildClassArgument(builder, source.parameterType(source.parameterCount() - 1));
+ builder
+ .append(", ")
+ .append(spreadTypes.length);
+
+ builder.append(");");
+
+ return builder.toString();
+ }
}
=====================================
src/main/java/com/headius/invokebinder/transform/Transform.java
=====================================
@@ -46,4 +46,109 @@ public abstract class Transform {
* @return a string representation of this transform
*/
public abstract String toString();
+
+ /**
+ * Return a Java code representation of this transform.
+ *
+ * @return a Java code representation of this transform.
+ */
+ public abstract String toJava(MethodType incoming);
+
+ /**
+ * Build a list of argument type classes suitable for inserting into Java code.
+ *
+ * This will be an argument list of the form "pkg.Cls1.class, pkg.Cls2[].class, primtype.class, ..."
+ *
+ * @param builder the builder in which to build the argument list
+ * @param types the classes from which to create the argument list
+ */
+ protected static void buildClassArguments(StringBuilder builder, Class<?>[] types) {
+ boolean second = false;
+ for (Class cls : types) {
+ if (second) builder.append(", ");
+ second = true;
+ buildClassArgument(builder, cls);
+ }
+ }
+
+ /**
+ * Build Java code to represent a single .class reference.
+ *
+ * This will be an argument of the form "pkg.Cls1.class" or "pkg.Cls2[].class" or "primtype.class"
+ *
+ * @param builder the builder in which to build the argument
+ * @param cls the type for the argument
+ */
+ protected static void buildClassArgument(StringBuilder builder, Class cls) {
+ buildClass(builder, cls);
+ builder.append(".class");
+ }
+
+ /**
+ * Build Java code to represent a cast to the given type.
+ *
+ * This will be an argument of the form "(pkg.Cls1)" or "(pkg.Cls2[])" or "(primtype)"
+ *
+ * @param builder the builder in which to build the argument
+ * @param cls the type for the argument
+ */
+ protected static void buildClassCast(StringBuilder builder, Class cls) {
+ builder.append('(');
+ buildClass(builder, cls);
+ builder.append(')');
+ }
+
+ /**
+ * Build Java code to represent a literal primitive.
+ *
+ * This will append L or F as appropriate for long and float primitives.
+ *
+ * @param builder the builder in which to generate the code
+ * @param value the primitive value to generate from
+ */
+ protected static void buildPrimitiveJava(StringBuilder builder, Object value) {
+ builder.append(value.toString());
+ if (value.getClass() == Float.class) builder.append('F');
+ if (value.getClass() == Long.class) builder.append('L');
+ }
+
+ /**
+ * Build Java code to represent a type reference to the given class.
+ *
+ * This will be of the form "pkg.Cls1" or "pkc.Cls2[]" or "primtype"..
+ *
+ * @param builder the builder in which to build the type reference
+ * @param cls the type for the reference
+ */
+ private static void buildClass(StringBuilder builder, Class cls) {
+ int arrayDims = 0;
+ Class tmp = cls;
+ while (tmp.isArray()) {
+ arrayDims++;
+ tmp = tmp.getComponentType();
+ }
+ builder.append(tmp.getName());
+ if (arrayDims > 0) {
+ for (; arrayDims > 0 ; arrayDims--) {
+ builder.append("[]");
+ }
+ }
+ }
+
+ /**
+ * Build Java code appropriate for standing up the given MethodType.
+ *
+ * @param source the MethodType for which to build Java code
+ * @return Java code suitable for building the given MethodType
+ */
+ public static String generateMethodType(MethodType source) {
+ StringBuilder builder = new StringBuilder("MethodType.methodType(");
+ buildClassArgument(builder, source.returnType());
+ if (source.parameterCount() > 0) {
+ builder.append(", ");
+ buildClassArguments(builder, source.parameterArray());
+ }
+ builder.append(")");
+ return builder.toString();
+ }
}
=====================================
src/main/java/com/headius/invokebinder/transform/TryFinally.java
=====================================
@@ -16,10 +16,12 @@
package com.headius.invokebinder.transform;
import com.headius.invokebinder.Binder;
+import com.headius.invokebinder.Util;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.lang.reflect.InvocationTargetException;
/**
* An try-finally transform.
@@ -34,11 +36,15 @@ public class TryFinally extends Transform {
private final MethodHandle post;
+ private static final MethodHandle tryFinallyJava9;
+
public TryFinally(MethodHandle post) {
this.post = post;
}
public MethodHandle up(MethodHandle target) {
+ if (Util.isJava9()) return nativeTryFinally(target, post);
+
MethodHandle exceptionHandler = Binder
.from(target.type().insertParameterTypes(0, Throwable.class).changeReturnType(void.class))
.drop(0)
@@ -72,6 +78,36 @@ public class TryFinally extends Transform {
return MethodHandles.foldArguments(realPost, target);
}
+ private MethodHandle nativeTryFinally(MethodHandle target, MethodHandle post) {
+ MethodType targetType = target.type();
+ boolean voidReturn = targetType.returnType() == Void.TYPE;
+ MethodType finallyType = targetType.insertParameterTypes(0, Throwable.class);
+ int dropCount = 1;
+
+ if (!voidReturn) {
+ finallyType = finallyType.insertParameterTypes(1, targetType.returnType());
+ dropCount = 2;
+ }
+
+ MethodHandle wrapPost = Binder
+ .from(finallyType)
+ .drop(0, dropCount)
+ .invoke(post);
+
+ if (!voidReturn) {
+ wrapPost = Binder.from(finallyType)
+ .foldVoid(wrapPost)
+ .permute(1)
+ .identity();
+ }
+
+ try {
+ return (MethodHandle) tryFinallyJava9.invokeExact(target, wrapPost);
+ } catch (Throwable t) {
+ throw new RuntimeException("Java 9 detected but MethodHandles.tryFinally missing", t);
+ }
+ }
+
public MethodType down(MethodType type) {
return type;
}
@@ -79,4 +115,16 @@ public class TryFinally extends Transform {
public String toString() {
return "try/finally with " + post;
}
+
+ public String toJava(MethodType incoming) {
+ throw new RuntimeException("TryFinally does not yet support toJava");
+ }
+
+ static {
+ if (Util.isJava9()) {
+ tryFinallyJava9 = Binder.from(MethodHandle.class, MethodHandle.class, MethodHandle.class).invokeStaticQuiet(MethodHandles.lookup(), MethodHandles.class, "tryFinally");
+ } else {
+ tryFinallyJava9 = null;
+ }
+ }
}
=====================================
src/main/java/com/headius/invokebinder/transform/Varargs.java
=====================================
@@ -59,4 +59,15 @@ public class Varargs extends Transform {
public String toString() {
return "varargs at " + index + " into " + arrayType.getName();
}
+
+ public String toJava(MethodType incoming) {
+ StringBuilder builder = new StringBuilder("handle = handle.asVarargsCollector(");
+
+ buildClassArgument(builder, arrayType);
+ builder.append(").asType(");
+ builder.append(generateMethodType(source));
+ builder.append(");");
+
+ return builder.toString();
+ }
}
=====================================
src/main/java/module-info.java
=====================================
@@ -0,0 +1,6 @@
+module com.headius.invokebinder {
+ requires java.base;
+ requires java.logging;
+
+ exports com.headius.invokebinder;
+}
\ No newline at end of file
=====================================
src/test/java/com/headius/invokebinder/BinderTest.java
=====================================
@@ -1,6 +1,8 @@
package com.headius.invokebinder;
import org.junit.Test;
+
+import static java.lang.invoke.MethodType.methodType;
import static org.junit.Assert.*;
import java.io.ByteArrayOutputStream;
@@ -8,7 +10,7 @@ import java.io.PrintStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
-import java.lang.invoke.MethodType;
+import java.lang.invoke.VarHandle;
import java.lang.reflect.Method;
/**
@@ -16,6 +18,7 @@ import java.lang.reflect.Method;
*/
public class BinderTest {
private static final Lookup LOOKUP = MethodHandles.lookup();
+
@Test
public void testFrom() throws Throwable {
MethodHandle target = Subjects.concatHandle();
@@ -29,7 +32,7 @@ public class BinderTest {
.insert(1, "world")
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type());
+ assertEquals(methodType(String.class, String.class, Object.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object()));
}
@@ -38,35 +41,35 @@ public class BinderTest {
Binder b1 = Binder
.from(void.class)
.insert(0, true);
- assertEquals(MethodType.methodType(void.class, boolean.class), b1.type());
+ assertEquals(methodType(void.class, boolean.class), b1.type());
Binder b2 = Binder
.from(void.class)
.insert(0, (byte)1);
- assertEquals(MethodType.methodType(void.class, byte.class), b2.type());
+ assertEquals(methodType(void.class, byte.class), b2.type());
Binder b3 = Binder
.from(void.class)
.insert(0, (short)1);
- assertEquals(MethodType.methodType(void.class, short.class), b3.type());
+ assertEquals(methodType(void.class, short.class), b3.type());
Binder b4 = Binder
.from(void.class)
.insert(0, (char)1);
- assertEquals(MethodType.methodType(void.class, char.class), b4.type());
+ assertEquals(methodType(void.class, char.class), b4.type());
Binder b5 = Binder
.from(void.class)
.insert(0, 1);
- assertEquals(MethodType.methodType(void.class, int.class), b5.type());
+ assertEquals(methodType(void.class, int.class), b5.type());
Binder b6 = Binder
.from(void.class)
.insert(0, 1L);
- assertEquals(MethodType.methodType(void.class, long.class), b6.type());
+ assertEquals(methodType(void.class, long.class), b6.type());
Binder b7 = Binder
.from(void.class)
.insert(0, 1.0F);
- assertEquals(MethodType.methodType(void.class, float.class), b7.type());
+ assertEquals(methodType(void.class, float.class), b7.type());
Binder b8 = Binder
.from(void.class)
.insert(0, 1.0);
- assertEquals(MethodType.methodType(void.class, double.class), b8.type());
+ assertEquals(methodType(void.class, double.class), b8.type());
MethodHandle target = intLongHandle();
@@ -75,7 +78,7 @@ public class BinderTest {
.insert(0, new Class[]{int.class, long.class}, 1, 1L)
.invoke(target);
- assertEquals(MethodType.methodType(String.class), handle.type());
+ assertEquals(methodType(String.class), handle.type());
assertEquals("intLong ok", (String) handle.invokeExact());
}
@@ -93,9 +96,9 @@ public class BinderTest {
Binder newBinder = thisBinder.to(otherBinder);
- assertEquals(MethodType.methodType(String.class, String.class, String.class), otherBinder.type());
- assertEquals(MethodType.methodType(String.class, String.class, int.class), thisBinder.type());
- assertEquals(MethodType.methodType(String.class, String.class, String.class), newBinder.type());
+ assertEquals(methodType(String.class, String.class, String.class), otherBinder.type());
+ assertEquals(methodType(String.class, String.class, int.class), thisBinder.type());
+ assertEquals(methodType(String.class, String.class, String.class), newBinder.type());
MethodHandle target = newBinder.invoke(Subjects.concatHandle());
@@ -107,12 +110,12 @@ public class BinderTest {
Binder binder = Binder
.from(String.class, String.class, Integer.class);
- assertEquals(MethodType.methodType(String.class, String.class, Integer.class), binder.type());
+ assertEquals(methodType(String.class, String.class, Integer.class), binder.type());
binder = binder
.drop(1);
- assertEquals(MethodType.methodType(String.class, String.class), binder.type());
+ assertEquals(methodType(String.class, String.class), binder.type());
}
@Test
@@ -142,7 +145,7 @@ public class BinderTest {
.insert(1, "world")
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, "));
MethodHandle target2 = Subjects.concatCharSequenceHandle();
@@ -151,7 +154,7 @@ public class BinderTest {
.insert(1, CharSequence.class, "world")
.invoke(target2);
- assertEquals(MethodType.methodType(String.class, String.class), handle2.type());
+ assertEquals(methodType(String.class, String.class), handle2.type());
assertEquals("Hello, world", (String) handle2.invokeExact("Hello, "));
}
@@ -164,7 +167,7 @@ public class BinderTest {
.drop(1)
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type());
+ assertEquals(methodType(String.class, String.class, Object.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object()));
MethodHandle target2 = Subjects.concatCharSequenceHandle();
@@ -174,7 +177,7 @@ public class BinderTest {
.drop(1)
.invoke(target2);
- assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle2.type());
+ assertEquals(methodType(String.class, String.class, Object.class), handle2.type());
assertEquals("Hello, world", (String) handle2.invokeExact("Hello, ", new Object()));
}
@@ -187,7 +190,7 @@ public class BinderTest {
.drop(1)
.invoke(target);
- assertEquals(MethodType.methodType(String.class, Object.class, String.class), handle.type());
+ assertEquals(methodType(String.class, Object.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact(new Object(), "world"));
MethodHandle target2 = Subjects.concatHandle();
@@ -197,7 +200,7 @@ public class BinderTest {
.drop(1)
.invoke(target2);
- assertEquals(MethodType.methodType(String.class, Object.class, String.class), handle2.type());
+ assertEquals(methodType(String.class, Object.class, String.class), handle2.type());
assertEquals("Hello, world", (String) handle2.invokeExact(new Object(), "world"));
}
@@ -210,7 +213,7 @@ public class BinderTest {
.insert(1, "world")
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type());
+ assertEquals(methodType(String.class, String.class, Object.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object()));
}
@@ -223,7 +226,7 @@ public class BinderTest {
.insert(1, "world")
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type());
+ assertEquals(methodType(String.class, String.class, Object.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object()));
handle = Binder
@@ -232,7 +235,7 @@ public class BinderTest {
.insert(1, "world")
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String.class, Object.class, double.class), handle.type());
+ assertEquals(methodType(String.class, String.class, Object.class, double.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object(), 1.0));
}
@@ -245,7 +248,7 @@ public class BinderTest {
.insert(1, "world")
.invoke(target);
- assertEquals(MethodType.methodType(String.class, Object.class, String.class), handle.type());
+ assertEquals(methodType(String.class, Object.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact(new Object(), "Hello, "));
handle = Binder
@@ -254,7 +257,7 @@ public class BinderTest {
.insert(1, "world")
.invoke(target);
- assertEquals(MethodType.methodType(String.class, Object.class, double.class, String.class), handle.type());
+ assertEquals(methodType(String.class, Object.class, double.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact(new Object(), 1.0, "Hello, "));
}
@@ -267,7 +270,7 @@ public class BinderTest {
.insert(0, "Hello, ", "world")
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type());
+ assertEquals(methodType(String.class, String.class, Object.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object()));
}
@@ -279,7 +282,7 @@ public class BinderTest {
.convert(target.type())
.invoke(target);
- assertEquals(MethodType.methodType(String.class, Object.class, Integer.class, Float.class), handle.type());
+ assertEquals(methodType(String.class, Object.class, Integer.class, Float.class), handle.type());
assertEquals(null, (String) handle.invokeExact((Object) "foo", (Integer) 5, (Float) 5.0f));
}
@@ -291,7 +294,7 @@ public class BinderTest {
.convert(target.type().returnType(), target.type().parameterArray())
.invoke(target);
- assertEquals(MethodType.methodType(String.class, Object.class, Integer.class, Float.class), handle.type());
+ assertEquals(methodType(String.class, Object.class, Integer.class, Float.class), handle.type());
assertEquals(null, (String)handle.invokeExact((Object)"foo", (Integer)5, (Float)5.0f));
}
@@ -303,7 +306,7 @@ public class BinderTest {
.cast(target.type())
.invoke(target);
- assertEquals(MethodType.methodType(String.class, Object.class, byte.class, int.class), handle.type());
+ assertEquals(methodType(String.class, Object.class, byte.class, int.class), handle.type());
assertEquals(null, (String)handle.invokeExact((Object)"foo", (byte)5, 5));
}
@@ -315,7 +318,7 @@ public class BinderTest {
.cast(target.type().returnType(), target.type().parameterArray())
.invoke(target);
- assertEquals(MethodType.methodType(String.class, Object.class, byte.class, int.class), handle.type());
+ assertEquals(methodType(String.class, Object.class, byte.class, int.class), handle.type());
assertEquals(null, (String)handle.invokeExact((Object)"foo", (byte)5, 5));
}
@@ -328,7 +331,7 @@ public class BinderTest {
.permute(0, 0)
.invoke(target);
- assertEquals(MethodType.methodType(String.class, Integer.class, Float.class, String.class), handle.type());
+ assertEquals(methodType(String.class, Integer.class, Float.class, String.class), handle.type());
assertEquals("foofoo", (String)handle.invokeExact((Integer) 0, (Float) 0.0f, "foo"));
}
@@ -340,7 +343,7 @@ public class BinderTest {
.spread(String.class, String.class)
.invoke(target);
- assertEquals(MethodType.methodType(String.class, Object[].class), handle.type());
+ assertEquals(methodType(String.class, Object[].class), handle.type());
assertEquals("foobar", (String)handle.invokeExact(new Object[] {"foo", "bar"}));
}
@@ -352,7 +355,7 @@ public class BinderTest {
.spread(2)
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String[].class), handle.type());
+ assertEquals(methodType(String.class, String[].class), handle.type());
assertEquals("foobar", (String)handle.invokeExact(new String[] {"foo", "bar"}));
}
@@ -363,7 +366,7 @@ public class BinderTest {
.collect(1, String[].class)
.invokeStatic(LOOKUP, BinderTest.class, "varargs");
- assertEquals(MethodType.methodType(String[].class, String.class, String.class, String.class), handle.type());
+ assertEquals(methodType(String[].class, String.class, String.class, String.class), handle.type());
String[] ary = (String[])handle.invokeExact("one", "two", "three");
assertEquals(2, ary.length);
assertEquals("two", ary[0]);
@@ -374,10 +377,38 @@ public class BinderTest {
.collect(1, 3, Integer[].class)
.invoke(Subjects.StringIntegersStringHandle);
- assertEquals(MethodType.methodType(String.class, String.class, Integer.class, Integer.class, Integer.class, String.class), handle2.type());
+ assertEquals(methodType(String.class, String.class, Integer.class, Integer.class, Integer.class, String.class), handle2.type());
assertEquals("[foo, [1, 2, 3], bar]", (String)handle2.invokeExact("foo", new Integer(1), new Integer(2), new Integer(3), "bar"));
}
+ public static String[] newStringArray(String s1, String s2) {
+ return new String[] {s1, s2};
+ }
+
+ public static MethodHandle newStringArrayHandle() throws Exception {
+ return LOOKUP.findStatic(BinderTest.class, "newStringArray", methodType(String[].class, String.class, String.class));
+ }
+
+ @Test
+ public void testCollectWithCollector() throws Throwable {
+ Binder binder = Binder
+ .from(String[].class, String.class, String.class, String.class)
+ .collect(1, String[].class, newStringArrayHandle());
+
+ String toJava = binder.toJava(methodType(String[].class, String.class, String.class, String.class));
+
+ assertTrue(toJava.contains("collectArguments"));
+
+ MethodHandle handle = binder
+ .invokeStatic(LOOKUP, BinderTest.class, "varargs");
+
+ assertEquals(methodType(String[].class, String.class, String.class, String.class), handle.type());
+ String[] ary = (String[])handle.invokeExact("one", "two", "three");
+ assertEquals(2, ary.length);
+ assertEquals("two", ary[0]);
+ assertEquals("three", ary[1]);
+ }
+
@Test
public void testVarargs() throws Throwable {
MethodHandle handle = Binder
@@ -385,14 +416,14 @@ public class BinderTest {
.varargs(1, String[].class)
.invokeStatic(LOOKUP, BinderTest.class, "varargs");
- assertEquals(MethodType.methodType(String[].class, String.class, String.class, String.class), handle.type());
+ assertEquals(methodType(String[].class, String.class, String.class, String.class), handle.type());
String[] ary = (String[])handle.invokeExact("one", "two", "three");
assertEquals(2, ary.length);
assertEquals("two", ary[0]);
assertEquals("three", ary[1]);
// from #2
- MethodHandle foo = Binder.from(MethodType.methodType(String.class, String.class))
+ MethodHandle foo = Binder.from(methodType(String.class, String.class))
.varargs(0, Object[].class)
.invokeStatic(MethodHandles.publicLookup(), getClass(), "varargs");
@@ -405,7 +436,7 @@ public class BinderTest {
.from(String.class)
.constant("hello");
- assertEquals(MethodType.methodType(String.class), handle.type());
+ assertEquals(methodType(String.class), handle.type());
assertEquals("hello", (String)handle.invokeExact());
}
@@ -415,7 +446,7 @@ public class BinderTest {
.from(Object.class)
.constant("hello");
- assertEquals(MethodType.methodType(Object.class), handle.type());
+ assertEquals(methodType(Object.class), handle.type());
assertEquals("hello", (Object)handle.invokeExact());
}
@@ -425,7 +456,7 @@ public class BinderTest {
.from(String.class, String.class)
.identity();
- assertEquals(MethodType.methodType(String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, String.class), handle.type());
assertEquals("hello", (String)handle.invokeExact("hello"));
}
@@ -441,7 +472,7 @@ public class BinderTest {
.fold(fold)
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, String.class), handle.type());
assertEquals("yahoofoo", (String)handle.invokeExact("foo"));
}
@@ -453,7 +484,7 @@ public class BinderTest {
.foldStatic(BinderTest.class, "alwaysYahooStatic")
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, String.class), handle.type());
assertEquals("yahoofoo", (String)handle.invokeExact("foo"));
}
@@ -467,23 +498,36 @@ public class BinderTest {
.drop(1)
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, String.class), handle.type());
assertEquals("yahoofoo", (String)handle.invokeExact("foo"));
}
@Test
public void testFilter() throws Throwable {
MethodHandle target = Subjects.concatHandle();
- MethodHandle filter = LOOKUP.findStatic(BinderTest.class, "addBaz", MethodType.methodType(String.class, String.class));
+ MethodHandle filter = LOOKUP.findStatic(BinderTest.class, "addBaz", methodType(String.class, String.class));
MethodHandle handle = Binder
.from(String.class, String.class, String.class)
.filter(0, filter, filter)
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, String.class, String.class), handle.type());
assertEquals("foobazbarbaz", (String)handle.invokeExact("foo", "bar"));
}
+ @Test
+ public void testFilterForward() throws Throwable {
+ MethodHandle target = LOOKUP.findStatic(Subjects.class, "twoIntsToString", methodType(String.class, int.class, int.class));
+ MethodHandle[] filters = {Subjects.nextInt, Subjects.nextInt};
+ MethodHandle handle = Binder.from(String.class, int.class, int.class)
+ .filterForward(0, filters)
+ .invoke(target);
+
+ int first = Subjects.counter.get();
+
+ assertEquals("(" + first + ", " + (first + 1) + ")", (String) handle.invokeExact(0, 0));
+ }
+
@Test
public void testInvoke() throws Throwable {
MethodHandle target = Subjects.concatHandle();
@@ -491,7 +535,7 @@ public class BinderTest {
.from(String.class, String.class, String.class)
.invoke(target);
- assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world"));
}
@@ -502,7 +546,7 @@ public class BinderTest {
.from(String.class, String.class, String.class)
.invoke(LOOKUP, target);
- assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world"));
}
@@ -513,7 +557,7 @@ public class BinderTest {
.from(String.class, String.class, String.class)
.invokeQuiet(LOOKUP, target);
- assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world"));
}
@@ -523,7 +567,7 @@ public class BinderTest {
.from(String.class, String.class, String.class)
.invokeStatic(LOOKUP, Subjects.class, "concatStatic");
- assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world"));
}
@@ -533,7 +577,7 @@ public class BinderTest {
.from(String.class, String.class, String.class)
.invokeStaticQuiet(LOOKUP, Subjects.class, "concatStatic");
- assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world"));
}
@@ -543,7 +587,7 @@ public class BinderTest {
.from(String.class, BinderTest.class, String.class, String.class)
.invokeVirtual(LOOKUP, "concatVirtual");
- assertEquals(MethodType.methodType(String.class, BinderTest.class, String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, BinderTest.class, String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact(this, "Hello, ", "world"));
}
@@ -553,7 +597,7 @@ public class BinderTest {
.from(String.class, BinderTest.class, String.class, String.class)
.invokeVirtualQuiet(LOOKUP, "concatVirtual");
- assertEquals(MethodType.methodType(String.class, BinderTest.class, String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, BinderTest.class, String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact(this, "Hello, ", "world"));
}
@@ -563,7 +607,7 @@ public class BinderTest {
.from(Constructable.class, String.class, String.class)
.invokeConstructor(LOOKUP, Constructable.class);
- assertEquals(MethodType.methodType(Constructable.class, String.class, String.class), handle.type());
+ assertEquals(methodType(Constructable.class, String.class, String.class), handle.type());
assertEquals(new Constructable("foo", "bar"), (Constructable) handle.invokeExact("foo", "bar"));
}
@@ -573,7 +617,7 @@ public class BinderTest {
.from(Constructable.class, String.class, String.class)
.invokeConstructorQuiet(LOOKUP, Constructable.class);
- assertEquals(MethodType.methodType(Constructable.class, String.class, String.class), handle.type());
+ assertEquals(methodType(Constructable.class, String.class, String.class), handle.type());
assertEquals(new Constructable("foo", "bar"), (Constructable) handle.invokeExact("foo", "bar"));
}
@@ -584,7 +628,7 @@ public class BinderTest {
.from(String.class, Fields.class)
.getField(LOOKUP, "instanceField");
- assertEquals(MethodType.methodType(String.class, Fields.class), handle.type());
+ assertEquals(methodType(String.class, Fields.class), handle.type());
assertEquals("initial", (String)handle.invokeExact(fields));
}
@@ -595,7 +639,7 @@ public class BinderTest {
.from(String.class, Fields.class)
.getFieldQuiet(LOOKUP, "instanceField");
- assertEquals(MethodType.methodType(String.class, Fields.class), handle.type());
+ assertEquals(methodType(String.class, Fields.class), handle.type());
assertEquals("initial", (String)handle.invokeExact(fields));
}
@@ -605,7 +649,7 @@ public class BinderTest {
.from(String.class)
.getStatic(LOOKUP, Fields.class, "staticField");
- assertEquals(MethodType.methodType(String.class), handle.type());
+ assertEquals(methodType(String.class), handle.type());
assertEquals("initial", (String)handle.invokeExact());
}
@@ -615,7 +659,7 @@ public class BinderTest {
.from(String.class)
.getStaticQuiet(LOOKUP, Fields.class, "staticField");
- assertEquals(MethodType.methodType(String.class), handle.type());
+ assertEquals(methodType(String.class), handle.type());
assertEquals("initial", (String)handle.invokeExact());
}
@@ -626,7 +670,7 @@ public class BinderTest {
.from(void.class, Fields.class, String.class)
.setField(LOOKUP, "instanceField");
- assertEquals(MethodType.methodType(void.class, Fields.class, String.class), handle.type());
+ assertEquals(methodType(void.class, Fields.class, String.class), handle.type());
handle.invokeExact(fields, "modified");
assertEquals("modified", fields.instanceField);
}
@@ -638,7 +682,7 @@ public class BinderTest {
.from(void.class, Fields.class, String.class)
.setFieldQuiet(LOOKUP, "instanceField");
- assertEquals(MethodType.methodType(void.class, Fields.class, String.class), handle.type());
+ assertEquals(methodType(void.class, Fields.class, String.class), handle.type());
handle.invokeExact(fields, "modified");
assertEquals("modified", fields.instanceField);
}
@@ -650,7 +694,7 @@ public class BinderTest {
.from(void.class, String.class)
.setStatic(LOOKUP, Fields.class, "staticField");
- assertEquals(MethodType.methodType(void.class, String.class), handle.type());
+ assertEquals(methodType(void.class, String.class), handle.type());
handle.invokeExact("modified");
assertEquals("modified", Fields.staticField);
} finally {
@@ -665,7 +709,7 @@ public class BinderTest {
.from(void.class, String.class)
.setStaticQuiet(LOOKUP, Fields.class, "staticField");
- assertEquals(MethodType.methodType(void.class, String.class), handle.type());
+ assertEquals(methodType(void.class, String.class), handle.type());
handle.invokeExact("modified");
assertEquals("modified", Fields.staticField);
} finally {
@@ -679,7 +723,7 @@ public class BinderTest {
.from(void.class, int.class, String.class)
.nop();
- assertEquals(MethodType.methodType(void.class, int.class, String.class), handle.type());
+ assertEquals(methodType(void.class, int.class, String.class), handle.type());
try {
handle.invokeExact(1, "foo");
} catch (Throwable t) {
@@ -693,7 +737,7 @@ public class BinderTest {
.from(void.class, BlahException.class)
.throwException();
- assertEquals(MethodType.methodType(void.class, BlahException.class), handle.type());
+ assertEquals(methodType(void.class, BlahException.class), handle.type());
try {
handle.invokeExact(new BlahException());
assertTrue("should not reach here", false);
@@ -712,7 +756,7 @@ public class BinderTest {
.tryFinally(post)
.invokeStatic(LOOKUP, BinderTest.class, "setZeroToFoo");
- assertEquals(MethodType.methodType(void.class, String[].class), handle.type());
+ assertEquals(methodType(void.class, String[].class), handle.type());
String[] stringAry = new String[1];
handle.invokeExact(stringAry);
assertEquals("foofinally", stringAry[0]);
@@ -729,7 +773,7 @@ public class BinderTest {
.tryFinally(post)
.invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooAndRaise");
- assertEquals(MethodType.methodType(void.class, String[].class), handle.type());
+ assertEquals(methodType(void.class, String[].class), handle.type());
String[] stringAry = new String[1];
try {
handle.invokeExact(stringAry);
@@ -755,7 +799,7 @@ public class BinderTest {
.catchException(BlahException.class, ignoreException)
.invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooAndRaise");
- assertEquals(MethodType.methodType(void.class, String[].class), handle.type());
+ assertEquals(methodType(void.class, String[].class), handle.type());
String[] stringAry = new String[1];
try {
handle.invokeExact(stringAry);
@@ -776,7 +820,7 @@ public class BinderTest {
.tryFinally(post)
.invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooReturnInt");
- assertEquals(MethodType.methodType(int.class, String[].class), handle.type());
+ assertEquals(methodType(int.class, String[].class), handle.type());
String[] stringAry = new String[1];
assertEquals(1, (int)handle.invokeExact(stringAry));
assertEquals("foofinally", stringAry[0]);
@@ -793,7 +837,7 @@ public class BinderTest {
.tryFinally(post)
.invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooReturnIntAndRaise");
- assertEquals(MethodType.methodType(int.class, String[].class), handle.type());
+ assertEquals(methodType(int.class, String[].class), handle.type());
String[] stringAry = new String[1];
try {
int x = (int)handle.invokeExact(stringAry);
@@ -820,7 +864,7 @@ public class BinderTest {
.catchException(BlahException.class, ignoreException)
.invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooReturnIntAndRaise");
- assertEquals(MethodType.methodType(int.class, String[].class), handle.type());
+ assertEquals(methodType(int.class, String[].class), handle.type());
String[] stringAry = new String[1];
try {
assertEquals(1, (int)handle.invokeExact(stringAry));
@@ -836,7 +880,7 @@ public class BinderTest {
.from(void.class, Object[].class, int.class, Object.class)
.arraySet();
- assertEquals(MethodType.methodType(void.class, Object[].class, int.class, Object.class), handle.type());
+ assertEquals(methodType(void.class, Object[].class, int.class, Object.class), handle.type());
Object[] ary = new Object[1];
handle.invokeExact(ary, 0, (Object)"foo");
assertEquals(ary[0], "foo");
@@ -848,10 +892,46 @@ public class BinderTest {
.from(Object.class, Object[].class, int.class)
.arrayGet();
- assertEquals(MethodType.methodType(Object.class, Object[].class, int.class), handle.type());
+ assertEquals(methodType(Object.class, Object[].class, int.class), handle.type());
Object[] ary = new Object[] {"foo"};
assertEquals(handle.invokeExact(ary, 0), "foo");
}
+
+ public static final VarHandle.AccessMode[] GET_ACCESS_MODES = new VarHandle.AccessMode[]{
+ VarHandle.AccessMode.GET,
+ VarHandle.AccessMode.GET_VOLATILE,
+ VarHandle.AccessMode.GET_ACQUIRE,
+ VarHandle.AccessMode.GET_OPAQUE};
+
+ public static final VarHandle.AccessMode[] SET_ACCESS_MODES = new VarHandle.AccessMode[]{
+ VarHandle.AccessMode.SET,
+ VarHandle.AccessMode.SET_VOLATILE,
+ VarHandle.AccessMode.SET_RELEASE,
+ VarHandle.AccessMode.SET_OPAQUE};
+
+ @Test
+ public void testArrayAccess() throws Throwable {
+ for (VarHandle.AccessMode mode : GET_ACCESS_MODES) {
+ MethodHandle handle = Binder
+ .from(Object.class, Object[].class, int.class)
+ .arrayAccess(mode);
+
+ assertEquals(methodType(Object.class, Object[].class, int.class), handle.type());
+ Object[] ary = new Object[]{"foo"};
+ assertEquals(handle.invokeExact(ary, 0), "foo");
+ }
+
+ for (VarHandle.AccessMode mode : SET_ACCESS_MODES) {
+ MethodHandle handle = Binder
+ .from(void.class, Object[].class, int.class, Object.class)
+ .arrayAccess(mode);
+
+ assertEquals(methodType(void.class, Object[].class, int.class, Object.class), handle.type());
+ Object[] ary = new Object[1];
+ handle.invokeExact(ary, 0, (Object) "foo");
+ assertEquals(ary[0], "foo");
+ }
+ }
@Test
public void testBranch() throws Throwable {
@@ -869,7 +949,7 @@ public class BinderTest {
.invokeStatic(LOOKUP, BinderTest.class, "addBaz")
);
- assertEquals(MethodType.methodType(String.class, String.class), handle.type());
+ assertEquals(methodType(String.class, String.class), handle.type());
assertEquals("foobar", (String)handle.invokeExact("foo"));
assertEquals("quuxbaz", (String)handle.invokeExact("quux"));
}
@@ -877,7 +957,7 @@ public class BinderTest {
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
public static MethodHandle intLongHandle() throws Exception {
- return LOOKUP.findStatic(BinderTest.class, "intLong", MethodType.methodType(String.class, int.class, long.class));
+ return LOOKUP.findStatic(BinderTest.class, "intLong", methodType(String.class, int.class, long.class));
}
public String concatVirtual(String a, String b) {
@@ -957,7 +1037,7 @@ public class BinderTest {
}
public static MethodHandle mixedHandle() throws Exception {
- return LOOKUP.findStatic(BinderTest.class, "mixed", MethodType.methodType(void.class, String.class, int.class, float.class));
+ return LOOKUP.findStatic(BinderTest.class, "mixed", methodType(void.class, String.class, int.class, float.class));
}
public static void mixed(String a, int b, float c) {
=====================================
src/test/java/com/headius/invokebinder/Subjects.java
=====================================
@@ -4,6 +4,7 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by headius on 1/25/14.
@@ -80,5 +81,17 @@ public class Subjects {
public static String upperCase(String x) {
return x.toUpperCase();
}
+
+ public static String twoIntsToString(int a, int b) {
+ return "(" + a + ", " + b + ")";
+ }
+
+ public static int nextInt(int ignored) {
+ return counter.getAndIncrement();
+ }
+
+ public static MethodHandle nextInt = Binder.from(int.class, int.class).invokeStaticQuiet(LOOKUP, Subjects.class, "nextInt");
+
+ public static final AtomicInteger counter = new AtomicInteger(0);
}
=====================================
src/test/java/com/headius/invokebinder/ToJavaTest.java
=====================================
@@ -0,0 +1,162 @@
+package com.headius.invokebinder;
+
+import com.headius.invokebinder.transform.Cast;
+import com.headius.invokebinder.transform.Catch;
+import com.headius.invokebinder.transform.Collect;
+import com.headius.invokebinder.transform.Convert;
+import com.headius.invokebinder.transform.Drop;
+import com.headius.invokebinder.transform.Filter;
+import com.headius.invokebinder.transform.FilterReturn;
+import com.headius.invokebinder.transform.Fold;
+import com.headius.invokebinder.transform.Insert;
+import com.headius.invokebinder.transform.Spread;
+import com.headius.invokebinder.transform.Transform;
+import com.headius.invokebinder.transform.Varargs;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+public class ToJavaTest {
+ @Test
+ public void testCast() {
+ Cast cast = new Cast(MethodType.methodType(String.class, Integer[].class, float.class));
+
+ String toJava = cast.toJava(null);
+
+ Assert.assertEquals("handle = MethodHandles.explicitCastArguments(handle, java.lang.Integer[].class, float.class);", toJava);
+ }
+
+ @Test
+ public void testCatch() {
+ Catch ctch = new Catch(RuntimeException.class, DUMMY_HANDLE);
+
+ String toJava = ctch.toJava(null);
+
+ Assert.assertEquals("handle = MethodHandles.catchException(handle, java.lang.RuntimeException.class, " + Catch.EXCEPTION_HANDLER_JAVA + ");", toJava);
+ }
+
+ @Test
+ public void testCollect() {
+ MethodType source = MethodType.methodType(void.class, int.class, int.class, int.class);
+ MethodType incoming = MethodType.methodType(void.class, int.class, int[].class);
+
+ Collect collect = new Collect(source, 1, int[].class);
+
+ String toJava = collect.toJava(incoming);
+
+ Assert.assertEquals("handle = handle.asCollector(int[].class, 2);", toJava);
+
+ collect = new Collect(source, 1, 1, int[].class);
+
+ toJava = collect.toJava(incoming);
+
+ String expected =
+ "handle = MethodHandles.permuteArguments(handle, MethodType.methodType(void.class, int.class, int.class, int[].class), new int[] {0, 1});\n" +
+ "handle = handle.asCollector(int[].class, 1);\n" +
+ "handle = MethodHandles.permuteArguments(handle, MethodType.methodType(void.class, int.class, int.class, int.class), new int[] {0, 2, 1});";
+
+ Assert.assertEquals(expected, toJava);
+ }
+
+ @Test
+ public void testConvert() {
+ MethodType source = MethodType.methodType(void.class, String.class);
+ MethodType incoming = MethodType.methodType(void.class, Object.class);
+
+ Convert convert = new Convert(source);
+
+ String toJava = convert.toJava(incoming);
+
+ String expected = "handle = MethodHandles.explicitCastArguments(handle.asType(MethodType.methodType(void.class, java.lang.String.class), MethodType.methodType(void.class, java.lang.String.class));";
+
+ Assert.assertEquals(expected, toJava);
+
+ source = MethodType.methodType(long.class, String.class);
+ incoming = MethodType.methodType(int.class, Object.class);
+
+ convert = new Convert(source);
+
+ toJava = convert.toJava(incoming);
+
+ Assert.assertEquals("handle = handle.asType(MethodType.methodType(long.class, java.lang.String.class));", toJava);
+ }
+
+ @Test
+ public void testDrop() {
+ MethodType incoming = MethodType.methodType(void.class);
+
+ Drop drop = new Drop(0, int.class, int.class, int.class);
+
+ String toJava = drop.toJava(incoming);
+
+ Assert.assertEquals("handle = MethodHandles.dropArguments(handle, 0, int.class, int.class, int.class);", toJava);
+ }
+
+ @Test
+ public void testFilter() {
+ Filter filter = new Filter(0, null);
+
+ String toJava = filter.toJava(DUMMY_HANDLE.type());
+
+ Assert.assertEquals("handle = MethodHandles.filterArguments(handle, 0, " + Filter.FILTER_FUNCTIONS_JAVA + ");", toJava);
+ }
+
+ @Test
+ public void testFilterReturn() {
+ FilterReturn filterReturn = new FilterReturn(DUMMY_HANDLE);
+
+ String toJava = filterReturn.toJava(null);
+
+ Assert.assertEquals("handle = MethodHandles.filterReturnValue(handle, " + FilterReturn.FILTER_FUNCTION_JAVA + ");", toJava);
+ }
+
+ @Test
+ public void testFold() {
+ Fold fold = new Fold(DUMMY_HANDLE);
+
+ String toJava = fold.toJava(null);
+
+ Assert.assertEquals("handle = MethodHandles.foldArguments(handle, " + Fold.FOLD_FUNCTION_JAVA + ");", toJava);
+ }
+
+ @Test
+ public void testInsert() {
+ Insert insert = new Insert(0, new Class[] {int.class, double.class, Object.class}, 1L, 1.0F, "hello");
+
+ String toJava = insert.toJava(null);
+
+ Assert.assertEquals("handle = MethodHandles.insertArguments(handle, 0, (int)1L, (double)1.0F, (java.lang.Object)value3);", toJava);
+ }
+
+ @Test
+ public void testSpread() {
+ Spread spread = new Spread(OBJECTARRAY_HANDLE.type(), Object.class, String.class, Integer.class);
+
+ String toJava = spread.toJava(null);
+
+ Assert.assertEquals("handle = handle.asSpreader(java.lang.Object[].class, 3);", toJava);
+ }
+
+ @Test
+ public void testVarargs() {
+ Varargs varargs = new Varargs(OBJECTS_HANDLE.type(), 0, Object[].class);
+
+ String toJava = varargs.toJava(null);
+
+ Assert.assertEquals("handle = handle.asVarargsCollector(java.lang.Object[].class).asType(" + Transform.generateMethodType(OBJECTS_HANDLE.type()) + ");", toJava);
+ }
+
+ public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+
+ private static final MethodHandle DUMMY_HANDLE = Binder.from(void.class).invokeStaticQuiet(LOOKUP, ToJavaTest.class, "dummy");
+ private static void dummy() {}
+
+ private static final MethodHandle OBJECTARRAY_HANDLE = Binder.from(void.class, Object[].class).invokeStaticQuiet(LOOKUP, ToJavaTest.class, "objectArray");
+ private static void objectArray(Object[] ary) {}
+
+ private static final MethodHandle OBJECTS_HANDLE = Binder.from(void.class, Object.class, Object.class, Object.class).invokeStaticQuiet(LOOKUP, ToJavaTest.class, "objects");
+ private static void objects(Object o, Object p, Object q) {}
+}
View it on GitLab: https://salsa.debian.org/java-team/invokebinder/-/commit/11486fa1b7bc5b3c407ebe988f890599c1b5beea
--
View it on GitLab: https://salsa.debian.org/java-team/invokebinder/-/commit/11486fa1b7bc5b3c407ebe988f890599c1b5beea
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20221026/afd55dd0/attachment.htm>
More information about the pkg-java-commits
mailing list