Update upstream source from tag 'upstream/1.12'
Update to upstream version '1.12'
with Debian dir efd1ae69ef130b1016ffd377cf779cd7bcb1549b
Jérôme Charaoui
1 year, 6 months ago
Binary diff not shown
0 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip |
0 | 0 | language: java |
1 | matrix: | |
2 | include: | |
3 | - os: linux | |
4 | arch: amd64 | |
5 | jdk: openjdk11 | |
6 | - os: linux | |
7 | arch: ppc64le | |
8 | jdk: openjdk11 |
0 | #!/bin/sh | |
1 | # ---------------------------------------------------------------------------- | |
2 | # Licensed to the Apache Software Foundation (ASF) under one | |
3 | # or more contributor license agreements. See the NOTICE file | |
4 | # distributed with this work for additional information | |
5 | # regarding copyright ownership. The ASF licenses this file | |
6 | # to you under the Apache License, Version 2.0 (the | |
7 | # "License"); you may not use this file except in compliance | |
8 | # with the License. You may obtain a copy of the License at | |
9 | # | |
10 | # http://www.apache.org/licenses/LICENSE-2.0 | |
11 | # | |
12 | # Unless required by applicable law or agreed to in writing, | |
13 | # software distributed under the License is distributed on an | |
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | # KIND, either express or implied. See the License for the | |
16 | # specific language governing permissions and limitations | |
17 | # under the License. | |
18 | # ---------------------------------------------------------------------------- | |
19 | ||
20 | # ---------------------------------------------------------------------------- | |
21 | # Maven2 Start Up Batch script | |
22 | # | |
23 | # Required ENV vars: | |
24 | # ------------------ | |
25 | # JAVA_HOME - location of a JDK home dir | |
26 | # | |
27 | # Optional ENV vars | |
28 | # ----------------- | |
29 | # M2_HOME - location of maven2's installed home dir | |
30 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven | |
31 | # e.g. to debug Maven itself, use | |
32 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 | |
33 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files | |
34 | # ---------------------------------------------------------------------------- | |
35 | ||
36 | if [ -z "$MAVEN_SKIP_RC" ] ; then | |
37 | ||
38 | if [ -f /etc/mavenrc ] ; then | |
39 | . /etc/mavenrc | |
40 | fi | |
41 | ||
42 | if [ -f "$HOME/.mavenrc" ] ; then | |
43 | . "$HOME/.mavenrc" | |
44 | fi | |
45 | ||
46 | fi | |
47 | ||
48 | # OS specific support. $var _must_ be set to either true or false. | |
49 | cygwin=false; | |
50 | darwin=false; | |
51 | mingw=false | |
52 | case "`uname`" in | |
53 | CYGWIN*) cygwin=true ;; | |
54 | MINGW*) mingw=true;; | |
55 | Darwin*) darwin=true | |
56 | # | |
57 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look | |
58 | # for the new JDKs provided by Oracle. | |
59 | # | |
60 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then | |
61 | # | |
62 | # Apple JDKs | |
63 | # | |
64 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home | |
65 | fi | |
66 | ||
67 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then | |
68 | # | |
69 | # Apple JDKs | |
70 | # | |
71 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home | |
72 | fi | |
73 | ||
74 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then | |
75 | # | |
76 | # Oracle JDKs | |
77 | # | |
78 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home | |
79 | fi | |
80 | ||
81 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then | |
82 | # | |
83 | # Apple JDKs | |
84 | # | |
85 | export JAVA_HOME=`/usr/libexec/java_home` | |
86 | fi | |
87 | ;; | |
88 | esac | |
89 | ||
90 | if [ -z "$JAVA_HOME" ] ; then | |
91 | if [ -r /etc/gentoo-release ] ; then | |
92 | JAVA_HOME=`java-config --jre-home` | |
93 | fi | |
94 | fi | |
95 | ||
96 | if [ -z "$M2_HOME" ] ; then | |
97 | ## resolve links - $0 may be a link to maven's home | |
98 | PRG="$0" | |
99 | ||
100 | # need this for relative symlinks | |
101 | while [ -h "$PRG" ] ; do | |
102 | ls=`ls -ld "$PRG"` | |
103 | link=`expr "$ls" : '.*-> \(.*\)$'` | |
104 | if expr "$link" : '/.*' > /dev/null; then | |
105 | PRG="$link" | |
106 | else | |
107 | PRG="`dirname "$PRG"`/$link" | |
108 | fi | |
109 | done | |
110 | ||
111 | saveddir=`pwd` | |
112 | ||
113 | M2_HOME=`dirname "$PRG"`/.. | |
114 | ||
115 | # make it fully qualified | |
116 | M2_HOME=`cd "$M2_HOME" && pwd` | |
117 | ||
118 | cd "$saveddir" | |
119 | # echo Using m2 at $M2_HOME | |
120 | fi | |
121 | ||
122 | # For Cygwin, ensure paths are in UNIX format before anything is touched | |
123 | if $cygwin ; then | |
124 | [ -n "$M2_HOME" ] && | |
125 | M2_HOME=`cygpath --unix "$M2_HOME"` | |
126 | [ -n "$JAVA_HOME" ] && | |
127 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` | |
128 | [ -n "$CLASSPATH" ] && | |
129 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` | |
130 | fi | |
131 | ||
132 | # For Migwn, ensure paths are in UNIX format before anything is touched | |
133 | if $mingw ; then | |
134 | [ -n "$M2_HOME" ] && | |
135 | M2_HOME="`(cd "$M2_HOME"; pwd)`" | |
136 | [ -n "$JAVA_HOME" ] && | |
137 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" | |
138 | # TODO classpath? | |
139 | fi | |
140 | ||
141 | if [ -z "$JAVA_HOME" ]; then | |
142 | javaExecutable="`which javac`" | |
143 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then | |
144 | # readlink(1) is not available as standard on Solaris 10. | |
145 | readLink=`which readlink` | |
146 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then | |
147 | if $darwin ; then | |
148 | javaHome="`dirname \"$javaExecutable\"`" | |
149 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" | |
150 | else | |
151 | javaExecutable="`readlink -f \"$javaExecutable\"`" | |
152 | fi | |
153 | javaHome="`dirname \"$javaExecutable\"`" | |
154 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` | |
155 | JAVA_HOME="$javaHome" | |
156 | export JAVA_HOME | |
157 | fi | |
158 | fi | |
159 | fi | |
160 | ||
161 | if [ -z "$JAVACMD" ] ; then | |
162 | if [ -n "$JAVA_HOME" ] ; then | |
163 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | |
164 | # IBM's JDK on AIX uses strange locations for the executables | |
165 | JAVACMD="$JAVA_HOME/jre/sh/java" | |
166 | else | |
167 | JAVACMD="$JAVA_HOME/bin/java" | |
168 | fi | |
169 | else | |
170 | JAVACMD="`which java`" | |
171 | fi | |
172 | fi | |
173 | ||
174 | if [ ! -x "$JAVACMD" ] ; then | |
175 | echo "Error: JAVA_HOME is not defined correctly." >&2 | |
176 | echo " We cannot execute $JAVACMD" >&2 | |
177 | exit 1 | |
178 | fi | |
179 | ||
180 | if [ -z "$JAVA_HOME" ] ; then | |
181 | echo "Warning: JAVA_HOME environment variable is not set." | |
182 | fi | |
183 | ||
184 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher | |
185 | ||
186 | # For Cygwin, switch paths to Windows format before running java | |
187 | if $cygwin; then | |
188 | [ -n "$M2_HOME" ] && | |
189 | M2_HOME=`cygpath --path --windows "$M2_HOME"` | |
190 | [ -n "$JAVA_HOME" ] && | |
191 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` | |
192 | [ -n "$CLASSPATH" ] && | |
193 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` | |
194 | fi | |
195 | ||
196 | # traverses directory structure from process work directory to filesystem root | |
197 | # first directory with .mvn subdirectory is considered project base directory | |
198 | find_maven_basedir() { | |
199 | local basedir=$(pwd) | |
200 | local wdir=$(pwd) | |
201 | while [ "$wdir" != '/' ] ; do | |
202 | if [ -d "$wdir"/.mvn ] ; then | |
203 | basedir=$wdir | |
204 | break | |
205 | fi | |
206 | wdir=$(cd "$wdir/.."; pwd) | |
207 | done | |
208 | echo "${basedir}" | |
209 | } | |
210 | ||
211 | # concatenates all lines of a file | |
212 | concat_lines() { | |
213 | if [ -f "$1" ]; then | |
214 | echo "$(tr -s '\n' ' ' < "$1")" | |
215 | fi | |
216 | } | |
217 | ||
218 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} | |
219 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" | |
220 | ||
221 | # Provide a "standardized" way to retrieve the CLI args that will | |
222 | # work with both Windows and non-Windows executions. | |
223 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" | |
224 | export MAVEN_CMD_LINE_ARGS | |
225 | ||
226 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain | |
227 | ||
228 | exec "$JAVACMD" \ | |
229 | $MAVEN_OPTS \ | |
230 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ | |
231 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ | |
232 | ${WRAPPER_LAUNCHER} $MAVEN_CMD_LINE_ARGS | |
233 |
2 | 2 | <groupId>com.headius</groupId> |
3 | 3 | <artifactId>invokebinder</artifactId> |
4 | 4 | <packaging>bundle</packaging> |
5 | <version>1.7</version> | |
5 | <version>1.12</version> | |
6 | 6 | <name>invokebinder</name> |
7 | 7 | <url>http://maven.apache.org</url> |
8 | 8 | |
50 | 50 | <Export-Package>com.headius.invokebinder.*</Export-Package> |
51 | 51 | </instructions> |
52 | 52 | </configuration> |
53 | <!-- https://issues.apache.org/jira/browse/FELIX-5698 --> | |
54 | <dependencies> | |
55 | <dependency> | |
56 | <groupId>biz.aQute.bnd</groupId> | |
57 | <artifactId>biz.aQute.bndlib</artifactId> | |
58 | <version>5.2.0</version> | |
59 | </dependency> | |
60 | </dependencies> | |
53 | 61 | </plugin> |
54 | 62 | <plugin> |
55 | 63 | <groupId>org.apache.maven.plugins</groupId> |
56 | 64 | <artifactId>maven-compiler-plugin</artifactId> |
57 | <version>2.0.2</version> | |
65 | <version>3.7.0</version> | |
66 | <executions> | |
67 | <execution> | |
68 | <id>default-compile</id> | |
69 | <configuration> | |
70 | <includes> | |
71 | <include>module-info.java</include> | |
72 | </includes> | |
73 | <release>9</release> | |
74 | </configuration> | |
75 | </execution> | |
76 | <execution> | |
77 | <id>base-compile</id> | |
78 | <goals> | |
79 | <goal>compile</goal> | |
80 | </goals> | |
81 | <configuration> | |
82 | <excludes> | |
83 | <exclude>module-info.java</exclude> | |
84 | </excludes> | |
85 | </configuration> | |
86 | </execution> | |
87 | </executions> | |
58 | 88 | <configuration> |
59 | 89 | <source>1.7</source> |
60 | 90 | <target>1.7</target> |
61 | <encoding>${project.build.sourceEncoding}</encoding> | |
62 | 91 | </configuration> |
63 | 92 | </plugin> |
64 | 93 | <plugin> |
69 | 98 | <encoding>${project.build.sourceEncoding}</encoding> |
70 | 99 | </configuration> |
71 | 100 | </plugin> |
101 | <plugin> | |
102 | <artifactId>maven-javadoc-plugin</artifactId> | |
103 | <version>3.2.0</version> | |
104 | <configuration> | |
105 | <source>8</source> | |
106 | </configuration> | |
107 | </plugin> | |
72 | 108 | </plugins> |
73 | 109 | </build> |
74 | 110 | |
76 | 112 | <dependency> |
77 | 113 | <groupId>junit</groupId> |
78 | 114 | <artifactId>junit</artifactId> |
79 | <version>4.9</version> | |
115 | <version>4.13.1</version> | |
80 | 116 | <scope>test</scope> |
81 | 117 | </dependency> |
82 | 118 | </dependencies> |
33 | 33 | import java.lang.invoke.MethodHandle; |
34 | 34 | import java.lang.invoke.MethodHandles; |
35 | 35 | import java.lang.invoke.MethodType; |
36 | import java.lang.invoke.VarHandle; | |
36 | 37 | import java.lang.reflect.Method; |
37 | import java.util.ArrayList; | |
38 | 38 | import java.util.Arrays; |
39 | import java.util.LinkedList; | |
39 | 40 | import java.util.List; |
40 | 41 | import java.util.ListIterator; |
41 | 42 | import java.util.logging.Logger; |
67 | 68 | public class Binder { |
68 | 69 | |
69 | 70 | private final Logger logger = Logger.getLogger("Invoke Binder"); |
70 | private final List<Transform> transforms = new ArrayList<>(); | |
71 | private final List<MethodType> types = new ArrayList<>(); | |
71 | private final List<Transform> transforms = new LinkedList<>(); | |
72 | private final List<MethodType> types = new LinkedList<>(); | |
72 | 73 | private final MethodType start; |
73 | 74 | private final MethodHandles.Lookup lookup; |
74 | 75 | |
879 | 880 | } |
880 | 881 | |
881 | 882 | /** |
883 | * Box all incoming arguments from the given position onward into the given array type. | |
884 | * | |
885 | * @param index the index from which to start boxing args | |
886 | * @param type the array type into which the args will be boxed | |
887 | * @param collector a function to use for collecting the arguments | |
888 | * @return a new Binder | |
889 | */ | |
890 | public Binder collect(int index, Class<?> type, MethodHandle collector) { | |
891 | return new Binder(this, new Collect(type(), index, type, collector)); | |
892 | } | |
893 | ||
894 | /** | |
882 | 895 | * Box a range of incoming arguments into the given array type. |
883 | 896 | * |
884 | 897 | * @param index the index from which to start boxing args |
891 | 904 | } |
892 | 905 | |
893 | 906 | /** |
907 | * Box a range of incoming arguments into the given array type using the given constructor to construct the array. | |
908 | * | |
909 | * The collector signature should match (T1, ..., Tn) where T is the type of the arguments being collected and n | |
910 | * is the number of arguments being collected. | |
911 | * | |
912 | * @param index the index from which to start boxing args | |
913 | * @param count the count of arguments to box | |
914 | * @param type the array type into which the args will be boxed | |
915 | * @param collector a function to use for collecting the arguments | |
916 | * @return a new Binder | |
917 | */ | |
918 | public Binder collect(int index, int count, Class<?> type, MethodHandle collector) { | |
919 | return new Binder(this, new Collect(type(), index, count, type, collector)); | |
920 | } | |
921 | ||
922 | /** | |
894 | 923 | * Box all incoming arguments from the given position onward into the given array type. |
895 | 924 | * This version accepts a variable number of incoming arguments. |
896 | 925 | * |
926 | 955 | return new Binder(this, new Fold(function)); |
927 | 956 | } |
928 | 957 | |
958 | /** | |
959 | * Process the incoming arguments using the given handle, leaving the argument list | |
960 | * unmodified. | |
961 | * | |
962 | * @param function the function that will process the incoming arguments. Its | |
963 | * signature must match the current signature's arguments exactly. | |
964 | * @return a new Binder | |
965 | */ | |
929 | 966 | public Binder foldVoid(MethodHandle function) { |
930 | 967 | if (type().returnType() == void.class) { |
931 | 968 | return fold(function); |
983 | 1020 | } |
984 | 1021 | |
985 | 1022 | /** |
986 | * Filter incoming arguments, starting at the given index, replacing each with the | |
987 | * result of calling the associated function in the given list. | |
1023 | * Filter incoming arguments, from the given index, replacing each with the | |
1024 | * result of calling the associated function in the given list. Note that | |
1025 | * the order in which the filters are applied is undefined; OpenJDK produces | |
1026 | * handles that execute them in reverse order. | |
1027 | * | |
1028 | * @see #filterForward(int, MethodHandle...) | |
988 | 1029 | * |
989 | 1030 | * @param index the index of the first argument to filter |
990 | 1031 | * @param functions the array of functions to transform the arguments |
992 | 1033 | */ |
993 | 1034 | public Binder filter(int index, MethodHandle... functions) { |
994 | 1035 | return new Binder(this, new Filter(index, functions)); |
1036 | } | |
1037 | ||
1038 | /** | |
1039 | * Filter incoming arguments, from the given index, replacing each with the | |
1040 | * result of calling the associated function in the given list. This version | |
1041 | * guarantees left-to-right evaluation of filter functions, potentially at | |
1042 | * the cost of a more complex handle tree. | |
1043 | * | |
1044 | * @param index the index of the first argument to filter | |
1045 | * @param functions the array of functions to transform the arguments | |
1046 | * @return a new Binder | |
1047 | */ | |
1048 | public Binder filterForward(int index, MethodHandle... functions) { | |
1049 | Binder filtered = this; | |
1050 | ||
1051 | for (int i = 0; i < functions.length; i++) { | |
1052 | filtered = filtered.filter(index + i, functions[i]); | |
1053 | } | |
1054 | ||
1055 | return filtered; | |
995 | 1056 | } |
996 | 1057 | |
997 | 1058 | /** |
1523 | 1584 | return invoke(MethodHandles.arrayElementSetter(type().parameterType(0))); |
1524 | 1585 | } |
1525 | 1586 | |
1587 | /** | |
1588 | * Apply the chain of transforms and bind them to a volatile array element set. | |
1589 | * | |
1590 | * @see Binder#arraySet() | |
1591 | * @see VarHandle#setVolatile(Object...) | |
1592 | */ | |
1593 | public MethodHandle arraySetVolatile() { | |
1594 | return arrayAccess(VarHandle.AccessMode.SET_VOLATILE); | |
1595 | } | |
1596 | ||
1597 | /** | |
1598 | * Apply the chain of transforms and bind them to a release-fenced array element set. | |
1599 | * | |
1600 | * @see Binder#arraySet() | |
1601 | * @see VarHandle#setRelease(Object...) | |
1602 | */ | |
1603 | public MethodHandle arraySetAcquire() { | |
1604 | return arrayAccess(VarHandle.AccessMode.SET_RELEASE); | |
1605 | } | |
1606 | ||
1607 | /** | |
1608 | * Apply the chain of transforms and bind them to an opaque (no ordering guarantee) array element set. | |
1609 | * | |
1610 | * @see Binder#arraySet() | |
1611 | * @see VarHandle#setVolatile(Object...) | |
1612 | */ | |
1613 | public MethodHandle arraySetOpaque() { | |
1614 | return arrayAccess(VarHandle.AccessMode.SET_OPAQUE); | |
1615 | } | |
1616 | ||
1526 | 1617 | |
1527 | 1618 | /** |
1528 | 1619 | * Apply the chain of transforms and bind them to an array element get. The signature |
1533 | 1624 | */ |
1534 | 1625 | public MethodHandle arrayGet() { |
1535 | 1626 | return invoke(MethodHandles.arrayElementGetter(type().parameterType(0))); |
1627 | } | |
1628 | ||
1629 | /** | |
1630 | * Apply the chain of transforms and bind them to a volatile array element get. | |
1631 | * | |
1632 | * @see Binder#arrayGet() | |
1633 | * @see VarHandle#getVolatile(Object...) | |
1634 | */ | |
1635 | public MethodHandle arrayGetVolatile() { | |
1636 | return arrayAccess(VarHandle.AccessMode.GET_VOLATILE); | |
1637 | } | |
1638 | ||
1639 | /** | |
1640 | * Apply the chain of transforms and bind them to an acquire-fenced array element get. | |
1641 | * | |
1642 | * @see Binder#arrayGet() | |
1643 | * @see VarHandle#getAcquire(Object...) | |
1644 | */ | |
1645 | public MethodHandle arrayGetAcquire() { | |
1646 | return arrayAccess(VarHandle.AccessMode.GET_ACQUIRE); | |
1647 | } | |
1648 | ||
1649 | /** | |
1650 | * Apply the chain of transforms and bind them to an opaque (no ordering guarantee) array element get. | |
1651 | * | |
1652 | * @see Binder#arrayGet() | |
1653 | * @see VarHandle#getVolatile(Object...) | |
1654 | */ | |
1655 | public MethodHandle arrayGetOpaque() { | |
1656 | return arrayAccess(VarHandle.AccessMode.GET_OPAQUE); | |
1657 | } | |
1658 | ||
1659 | /** | |
1660 | * Apply the chain of transforms and bind them to an array varhandle operation. The | |
1661 | * signature at the endpoint must match the VarHandle access type passed in. | |
1662 | */ | |
1663 | public MethodHandle arrayAccess(VarHandle.AccessMode mode) { | |
1664 | return invoke(MethodHandles.arrayElementVarHandle(type().parameterType(0)).toMethodHandle(mode)); | |
1536 | 1665 | } |
1537 | 1666 | |
1538 | 1667 | /** |
1559 | 1688 | return invoke(MethodHandles.invoker(start)); |
1560 | 1689 | } |
1561 | 1690 | |
1691 | /** | |
1692 | * Produce Java code that would perform equivalent operations to this binder. | |
1693 | * | |
1694 | * @return Java code for the handle adaptations this Binder would produce. | |
1695 | */ | |
1696 | public String toJava(MethodType incoming) { | |
1697 | StringBuilder builder = new StringBuilder(); | |
1698 | boolean second = false; | |
1699 | for (Transform transform : transforms) { | |
1700 | if (second) builder.append('\n'); | |
1701 | second = true; | |
1702 | builder.append(transform.toJava(incoming)); | |
1703 | } | |
1704 | return builder.toString(); | |
1705 | } | |
1706 | ||
1562 | 1707 | } |
787 | 787 | return offsets; |
788 | 788 | } |
789 | 789 | |
790 | @Override | |
791 | public boolean equals(Object o) { | |
792 | if (this == o) return true; | |
793 | if (o == null || getClass() != o.getClass()) return false; | |
794 | ||
795 | Signature signature = (Signature) o; | |
796 | ||
797 | if (!methodType.equals(signature.methodType)) return false; | |
798 | ||
799 | return Arrays.equals(argNames, signature.argNames); | |
800 | } | |
801 | ||
802 | @Override | |
803 | public int hashCode() { | |
804 | int result = methodType.hashCode(); | |
805 | result = 31 * result + Arrays.hashCode(argNames); | |
806 | return result; | |
807 | } | |
790 | 808 | } |
852 | 852 | return new SmartBinder(this, newSignature, binder.collect(index, signature().argCount() - (newSignature.argCount() - 1), Array.newInstance(signature().argType(index), 0).getClass())); |
853 | 853 | } |
854 | 854 | |
855 | /** | |
856 | * Collect arguments matching namePattern into an trailing array argument | |
857 | * named outName, using collector to construct the array object. | |
858 | * | |
859 | * The collector signature should match (T1, ..., Tn) where T is the type of the arguments being collected and n | |
860 | * is the number of arguments being collected. | |
861 | * | |
862 | * The namePattern is a standard regular expression. | |
863 | * | |
864 | * @param outName the name of the new array argument | |
865 | * @param namePattern a pattern with which to match arguments for collecting | |
866 | * @param collector a function to use for collecting the arguments | |
867 | * @return a new SmartBinder with the collect applied | |
868 | */ | |
869 | public SmartBinder collect(String outName, String namePattern, MethodHandle collector) { | |
870 | int index = signature().argOffsets(namePattern); | |
871 | ||
872 | assert index >= 0 : "no arguments matching " + namePattern + " found in signature " + signature(); | |
873 | ||
874 | Signature newSignature = signature().collect(outName, namePattern); | |
875 | ||
876 | return new SmartBinder(this, newSignature, binder.collect(index, signature().argCount() - (newSignature.argCount() - 1), Array.newInstance(signature().argType(index), 0).getClass(), collector)); | |
877 | } | |
878 | ||
855 | 879 | /////////////////////////////////////////////////////////////////////////// |
856 | 880 | // CASTS, based on MethodHandles.explicitCastArguments and MethodHandle.asType. |
857 | 881 | /////////////////////////////////////////////////////////////////////////// |
1164 | 1188 | |
1165 | 1189 | return new SmartBinder(newSig, newBinder); |
1166 | 1190 | } |
1191 | ||
1192 | /** | |
1193 | * @see Binder#tryFinally(MethodHandle) | |
1194 | */ | |
1195 | public SmartBinder tryFinally(MethodHandle post) { | |
1196 | return new SmartBinder(this, signature(), binder.tryFinally(post)); | |
1197 | } | |
1167 | 1198 | } |
0 | package com.headius.invokebinder; | |
1 | ||
2 | /** | |
3 | * Utilities used by InvokeBinder classes. | |
4 | */ | |
5 | public class Util { | |
6 | public static boolean IS_JAVA9; | |
7 | ||
8 | static { | |
9 | boolean isJava9; | |
10 | try { | |
11 | Class.forName("java.lang.Module"); | |
12 | isJava9 = true; | |
13 | } catch (Exception e) { | |
14 | isJava9 = false; | |
15 | } | |
16 | IS_JAVA9 = isJava9; | |
17 | } | |
18 | ||
19 | public static boolean isJava9() { | |
20 | return IS_JAVA9; | |
21 | } | |
22 | } |
53 | 53 | public String toString() { |
54 | 54 | return "cast args to " + type; |
55 | 55 | } |
56 | ||
57 | public String toJava(MethodType incoming) { | |
58 | StringBuilder builder = new StringBuilder("handle = MethodHandles.explicitCastArguments(handle, "); | |
59 | buildClassArguments(builder, type.parameterArray()); | |
60 | builder.append(");"); | |
61 | return builder.toString(); | |
62 | } | |
63 | ||
56 | 64 | } |
25 | 25 | */ |
26 | 26 | public class Catch extends Transform { |
27 | 27 | |
28 | public static final String EXCEPTION_HANDLER_JAVA = "<exception handler>"; | |
28 | 29 | private final Class<? extends Throwable> throwable; |
29 | 30 | private final MethodHandle function; |
30 | 31 | |
44 | 45 | public String toString() { |
45 | 46 | return "catch exception type " + throwable + " using " + function; |
46 | 47 | } |
48 | ||
49 | public String toJava(MethodType incoming) { | |
50 | StringBuilder builder = new StringBuilder("handle = MethodHandles.catchException(handle, "); | |
51 | buildClassArgument(builder, throwable); | |
52 | builder.append(", ").append(EXCEPTION_HANDLER_JAVA).append(");"); | |
53 | return builder.toString(); | |
54 | } | |
47 | 55 | } |
17 | 17 | import com.headius.invokebinder.Binder; |
18 | 18 | |
19 | 19 | import java.lang.invoke.MethodHandle; |
20 | import java.lang.invoke.MethodHandles; | |
20 | 21 | import java.lang.invoke.MethodType; |
21 | 22 | |
22 | 23 | /** |
23 | 24 | * An argument-boxing transform with a fixed incoming size. |
24 | 25 | * |
25 | * Equivalent call: MethodHandle.asCollector(Class, int) | |
26 | * Equivalent call: MethodHandle.asCollector(Class, int) or MethodHandles.collectArguments | |
26 | 27 | */ |
27 | 28 | public class Collect extends Transform { |
28 | 29 | |
30 | 31 | private final int index; |
31 | 32 | private final int count; |
32 | 33 | private final Class<?> arrayType; |
34 | private final MethodHandle collector; | |
33 | 35 | |
34 | 36 | public Collect(MethodType source, int index, Class<?> arrayType) { |
35 | 37 | this.source = source; |
36 | 38 | this.index = index; |
37 | 39 | this.count = source.parameterCount() - index; |
38 | 40 | this.arrayType = arrayType; |
41 | this.collector = null; | |
42 | } | |
43 | ||
44 | public Collect(MethodType source, int index, Class<?> arrayType, MethodHandle collector) { | |
45 | this.source = source; | |
46 | this.index = index; | |
47 | this.count = source.parameterCount() - index; | |
48 | this.arrayType = arrayType; | |
49 | this.collector = collector; | |
39 | 50 | } |
40 | 51 | |
41 | 52 | public Collect(MethodType source, int index, int count, Class<?> arrayType) { |
43 | 54 | this.index = index; |
44 | 55 | this.count = count; |
45 | 56 | this.arrayType = arrayType; |
57 | this.collector = null; | |
58 | } | |
59 | ||
60 | public Collect(MethodType source, int index, int count, Class<?> arrayType, MethodHandle collector) { | |
61 | this.source = source; | |
62 | this.index = index; | |
63 | this.count = count; | |
64 | this.arrayType = arrayType; | |
65 | this.collector = collector; | |
46 | 66 | } |
47 | 67 | |
48 | 68 | public MethodHandle up(MethodHandle target) { |
49 | if (index + count == source.parameterCount()) { | |
69 | if (onlyTail()) { | |
50 | 70 | // fast path for tail args |
51 | return target.asCollector(arrayType, count); | |
52 | } else { | |
53 | int[] movePermute = new int[source.parameterCount()]; | |
54 | int[] moveBackPermute = new int[target.type().parameterCount()]; | |
55 | // pre | |
56 | for (int i = 0; i < index; i++) { | |
57 | movePermute[i] = i; | |
58 | moveBackPermute[i] = i; | |
71 | if (collector == null) { | |
72 | return target.asCollector(arrayType, count); | |
59 | 73 | } |
60 | 74 | |
61 | // post | |
62 | int shifted = 0; | |
63 | for (int i = index; i + count < movePermute.length; i++, shifted++) movePermute[i] = i + count; | |
64 | for (int i = index; i + 1 < moveBackPermute.length; i++) moveBackPermute[i + 1] = i; | |
75 | return MethodHandles.collectArguments(target, index, collector); | |
76 | } else { | |
77 | Permutes permutes = buildPermutes(source, target.type()); | |
65 | 78 | |
66 | // collected args | |
67 | for (int i = index + shifted; i < movePermute.length; i++) movePermute[i] = i - shifted; | |
68 | moveBackPermute[index] = moveBackPermute.length - 1; | |
79 | Binder binder = preparePermuteBinder(permutes); | |
80 | return binder.invoke(target); | |
81 | } | |
82 | } | |
69 | 83 | |
70 | return Binder.from(source) | |
71 | .permute(movePermute) | |
72 | .collect(source.parameterCount() - count, arrayType) | |
73 | .permute(moveBackPermute) | |
74 | .invoke(target); | |
75 | } | |
84 | private Binder preparePermuteBinder(Permutes permutes) { | |
85 | return Binder.from(source) | |
86 | .permute(permutes.movePermute) | |
87 | .collect(source.parameterCount() - count, arrayType, collector) | |
88 | .permute(permutes.moveBackPermute); | |
76 | 89 | } |
77 | 90 | |
78 | 91 | public MethodType down(MethodType type) { |
95 | 108 | public String toString() { |
96 | 109 | return "collect at " + index + " into " + arrayType.getName(); |
97 | 110 | } |
111 | ||
112 | public String toJava(MethodType incoming) { | |
113 | StringBuilder builder = new StringBuilder(); | |
114 | if (onlyTail()) { | |
115 | if (collector == null) { | |
116 | builder.append("handle = handle.asCollector("); | |
117 | buildClassArgument(builder, arrayType); | |
118 | builder | |
119 | .append(", ") | |
120 | .append(count) | |
121 | .append(");"); | |
122 | } else { | |
123 | builder.append("handle = MethodHandles.collectArguments("); | |
124 | ||
125 | builder | |
126 | .append("handle, ") | |
127 | .append(count) | |
128 | .append(", "); | |
129 | ||
130 | buildClassArgument(builder, arrayType); | |
131 | ||
132 | builder.append(");"); | |
133 | } | |
134 | } else { | |
135 | Permutes permutes = buildPermutes(source, incoming); | |
136 | ||
137 | Binder binder = preparePermuteBinder(permutes); | |
138 | return binder.toJava(incoming); | |
139 | } | |
140 | return builder.toString(); | |
141 | } | |
142 | ||
143 | private boolean onlyTail() { | |
144 | return index + count == source.parameterCount(); | |
145 | } | |
146 | ||
147 | private static class Permutes { | |
148 | private final int[] movePermute; | |
149 | private final int[] moveBackPermute; | |
150 | ||
151 | private Permutes(MethodType source, MethodType target, int index, int count) { | |
152 | movePermute = new int[source.parameterCount()]; | |
153 | moveBackPermute = new int[target.parameterCount()]; | |
154 | // pre | |
155 | for (int i = 0; i < index; i++) { | |
156 | movePermute[i] = i; | |
157 | moveBackPermute[i] = i; | |
158 | } | |
159 | ||
160 | // post | |
161 | int shifted = 0; | |
162 | for (int i = index; i + count < movePermute.length; i++, shifted++) movePermute[i] = i + count; | |
163 | for (int i = index; i + 1 < moveBackPermute.length; i++) moveBackPermute[i + 1] = i; | |
164 | ||
165 | // collected args | |
166 | for (int i = index + shifted; i < movePermute.length; i++) movePermute[i] = i - shifted; | |
167 | moveBackPermute[index] = moveBackPermute.length - 1; | |
168 | } | |
169 | } | |
170 | ||
171 | private Permutes buildPermutes(MethodType source, MethodType target) { | |
172 | return new Permutes(source, target, index, count); | |
173 | } | |
98 | 174 | } |
52 | 52 | public String toString() { |
53 | 53 | return "convert args to " + type; |
54 | 54 | } |
55 | ||
56 | public String toJava(MethodType incoming) { | |
57 | String methodTypeJava = generateMethodType(type); | |
58 | ||
59 | if (incoming.returnType() == void.class) { | |
60 | return "handle = MethodHandles.explicitCastArguments(handle.asType(" + methodTypeJava + ", " + methodTypeJava + ");"; | |
61 | } | |
62 | ||
63 | return "handle = handle.asType(" + methodTypeJava + ");"; | |
64 | } | |
55 | 65 | } |
45 | 45 | public String toString() { |
46 | 46 | return "drop " + Arrays.toString(types) + " at " + position; |
47 | 47 | } |
48 | ||
49 | public String toJava(MethodType incoming) { | |
50 | StringBuilder builder = new StringBuilder("handle = MethodHandles.dropArguments(handle, "); | |
51 | ||
52 | builder.append(position).append(", "); | |
53 | buildClassArguments(builder, types); | |
54 | builder.append(");"); | |
55 | ||
56 | return builder.toString(); | |
57 | } | |
48 | 58 | } |
25 | 25 | * Equivalent call: MethodHandles.filterArguments(MethodHandle, int, MethodHandle...). |
26 | 26 | */ |
27 | 27 | public class Filter extends Transform { |
28 | ||
29 | 28 | private final int index; |
30 | 29 | private final MethodHandle[] functions; |
30 | ||
31 | public static final String FILTER_FUNCTIONS_JAVA = "<filter functions>"; | |
31 | 32 | |
32 | 33 | public Filter(int index, MethodHandle... functions) { |
33 | 34 | this.index = index; |
48 | 49 | public String toString() { |
49 | 50 | return "fold args from " + index + " with " + Arrays.toString(functions); |
50 | 51 | } |
52 | ||
53 | public String toJava(MethodType incoming) { | |
54 | return "handle = MethodHandles.filterArguments(handle, " + index + ", " + FILTER_FUNCTIONS_JAVA + ");"; | |
55 | } | |
51 | 56 | } |
26 | 26 | * Equivalent call: MethodHandles.filterReturn(MethodHandle, MethodHandle). |
27 | 27 | */ |
28 | 28 | public class FilterReturn extends Transform { |
29 | private final MethodHandle function; | |
29 | 30 | |
30 | private final MethodHandle function; | |
31 | public static final String FILTER_FUNCTION_JAVA = "<filter function>"; | |
31 | 32 | |
32 | 33 | public FilterReturn(MethodHandle function) { |
33 | 34 | this.function = function; |
52 | 53 | public String toString() { |
53 | 54 | return "filter return with " + function; |
54 | 55 | } |
56 | ||
57 | public String toJava(MethodType incoming) { | |
58 | return "handle = MethodHandles.filterReturnValue(handle, " + FILTER_FUNCTION_JAVA + ");"; | |
59 | } | |
55 | 60 | } |
24 | 24 | * Equivalent call: MethodHandles.foldArguments(MethodHandle, MethodHandle). |
25 | 25 | */ |
26 | 26 | public class Fold extends Transform { |
27 | private final MethodHandle function; | |
27 | 28 | |
28 | private final MethodHandle function; | |
29 | public static final String FOLD_FUNCTION_JAVA = "<fold function>"; | |
29 | 30 | |
30 | 31 | public Fold(MethodHandle function) { |
31 | 32 | this.function = function; |
43 | 44 | public String toString() { |
44 | 45 | return "fold args with " + function; |
45 | 46 | } |
47 | ||
48 | public String toJava(MethodType incoming) { | |
49 | return "handle = MethodHandles.foldArguments(handle, " + FOLD_FUNCTION_JAVA + ");"; | |
50 | } | |
46 | 51 | } |
106 | 106 | return "insert " + Arrays.toString(types()) + " at " + position; |
107 | 107 | } |
108 | 108 | |
109 | public String toJava(MethodType incoming) { | |
110 | StringBuilder builder = new StringBuilder("handle = MethodHandles.insertArguments(handle, "); | |
111 | builder | |
112 | .append(position) | |
113 | .append(", "); | |
114 | ||
115 | // we cast all arguments since natural type will frequently be wrong | |
116 | boolean second = false; | |
117 | for (int i = 0; i < types.length; i++) { | |
118 | if (second) builder.append(", "); | |
119 | second = true; | |
120 | ||
121 | buildClassCast(builder, types[i]); | |
122 | if (types[i].isPrimitive()) { | |
123 | buildPrimitiveJava(builder, values[i]); | |
124 | } else { | |
125 | builder.append("value").append(i + 1); | |
126 | } | |
127 | } | |
128 | builder.append(");"); | |
129 | ||
130 | return builder.toString(); | |
131 | } | |
132 | ||
109 | 133 | private Class<?>[] types() { |
110 | 134 | Class<?>[] types = new Class<?>[values.length]; |
111 | 135 | for (int i = 0; i < types.length; i++) { |
56 | 56 | public String toString() { |
57 | 57 | return "permute " + source + " with " + Arrays.toString(reorder); |
58 | 58 | } |
59 | ||
60 | public String toJava(MethodType incoming) { | |
61 | StringBuilder builder = new StringBuilder("handle = MethodHandles.permuteArguments(handle, "); | |
62 | ||
63 | String reorder = Arrays.toString(this.reorder); | |
64 | reorder = reorder.substring(1, reorder.length() - 1); | |
65 | ||
66 | builder.append(generateMethodType(source) + ", new int[] {" + reorder + "});"); | |
67 | ||
68 | return builder.toString(); | |
69 | } | |
70 | ||
59 | 71 | } |
51 | 51 | public String toString() { |
52 | 52 | return "spread " + source + " to " + down(source); |
53 | 53 | } |
54 | ||
55 | public String toJava(MethodType incoming) { | |
56 | StringBuilder builder = new StringBuilder("handle = handle.asSpreader("); | |
57 | ||
58 | buildClassArgument(builder, source.parameterType(source.parameterCount() - 1)); | |
59 | builder | |
60 | .append(", ") | |
61 | .append(spreadTypes.length); | |
62 | ||
63 | builder.append(");"); | |
64 | ||
65 | return builder.toString(); | |
66 | } | |
54 | 67 | } |
45 | 45 | * @return a string representation of this transform |
46 | 46 | */ |
47 | 47 | public abstract String toString(); |
48 | ||
49 | /** | |
50 | * Return a Java code representation of this transform. | |
51 | * | |
52 | * @return a Java code representation of this transform. | |
53 | */ | |
54 | public abstract String toJava(MethodType incoming); | |
55 | ||
56 | /** | |
57 | * Build a list of argument type classes suitable for inserting into Java code. | |
58 | * | |
59 | * This will be an argument list of the form "pkg.Cls1.class, pkg.Cls2[].class, primtype.class, ..." | |
60 | * | |
61 | * @param builder the builder in which to build the argument list | |
62 | * @param types the classes from which to create the argument list | |
63 | */ | |
64 | protected static void buildClassArguments(StringBuilder builder, Class<?>[] types) { | |
65 | boolean second = false; | |
66 | for (Class cls : types) { | |
67 | if (second) builder.append(", "); | |
68 | second = true; | |
69 | buildClassArgument(builder, cls); | |
70 | } | |
71 | } | |
72 | ||
73 | /** | |
74 | * Build Java code to represent a single .class reference. | |
75 | * | |
76 | * This will be an argument of the form "pkg.Cls1.class" or "pkg.Cls2[].class" or "primtype.class" | |
77 | * | |
78 | * @param builder the builder in which to build the argument | |
79 | * @param cls the type for the argument | |
80 | */ | |
81 | protected static void buildClassArgument(StringBuilder builder, Class cls) { | |
82 | buildClass(builder, cls); | |
83 | builder.append(".class"); | |
84 | } | |
85 | ||
86 | /** | |
87 | * Build Java code to represent a cast to the given type. | |
88 | * | |
89 | * This will be an argument of the form "(pkg.Cls1)" or "(pkg.Cls2[])" or "(primtype)" | |
90 | * | |
91 | * @param builder the builder in which to build the argument | |
92 | * @param cls the type for the argument | |
93 | */ | |
94 | protected static void buildClassCast(StringBuilder builder, Class cls) { | |
95 | builder.append('('); | |
96 | buildClass(builder, cls); | |
97 | builder.append(')'); | |
98 | } | |
99 | ||
100 | /** | |
101 | * Build Java code to represent a literal primitive. | |
102 | * | |
103 | * This will append L or F as appropriate for long and float primitives. | |
104 | * | |
105 | * @param builder the builder in which to generate the code | |
106 | * @param value the primitive value to generate from | |
107 | */ | |
108 | protected static void buildPrimitiveJava(StringBuilder builder, Object value) { | |
109 | builder.append(value.toString()); | |
110 | if (value.getClass() == Float.class) builder.append('F'); | |
111 | if (value.getClass() == Long.class) builder.append('L'); | |
112 | } | |
113 | ||
114 | /** | |
115 | * Build Java code to represent a type reference to the given class. | |
116 | * | |
117 | * This will be of the form "pkg.Cls1" or "pkc.Cls2[]" or "primtype". | |
118 | * | |
119 | * @param builder the builder in which to build the type reference | |
120 | * @param cls the type for the reference | |
121 | */ | |
122 | private static void buildClass(StringBuilder builder, Class cls) { | |
123 | int arrayDims = 0; | |
124 | Class tmp = cls; | |
125 | while (tmp.isArray()) { | |
126 | arrayDims++; | |
127 | tmp = tmp.getComponentType(); | |
128 | } | |
129 | builder.append(tmp.getName()); | |
130 | if (arrayDims > 0) { | |
131 | for (; arrayDims > 0 ; arrayDims--) { | |
132 | builder.append("[]"); | |
133 | } | |
134 | } | |
135 | } | |
136 | ||
137 | /** | |
138 | * Build Java code appropriate for standing up the given MethodType. | |
139 | * | |
140 | * @param source the MethodType for which to build Java code | |
141 | * @return Java code suitable for building the given MethodType | |
142 | */ | |
143 | public static String generateMethodType(MethodType source) { | |
144 | StringBuilder builder = new StringBuilder("MethodType.methodType("); | |
145 | buildClassArgument(builder, source.returnType()); | |
146 | if (source.parameterCount() > 0) { | |
147 | builder.append(", "); | |
148 | buildClassArguments(builder, source.parameterArray()); | |
149 | } | |
150 | builder.append(")"); | |
151 | return builder.toString(); | |
152 | } | |
48 | 153 | } |
15 | 15 | package com.headius.invokebinder.transform; |
16 | 16 | |
17 | 17 | import com.headius.invokebinder.Binder; |
18 | import com.headius.invokebinder.Util; | |
18 | 19 | |
19 | 20 | import java.lang.invoke.MethodHandle; |
20 | 21 | import java.lang.invoke.MethodHandles; |
21 | 22 | import java.lang.invoke.MethodType; |
23 | import java.lang.reflect.InvocationTargetException; | |
22 | 24 | |
23 | 25 | /** |
24 | 26 | * An try-finally transform. |
33 | 35 | |
34 | 36 | private final MethodHandle post; |
35 | 37 | |
38 | private static final MethodHandle tryFinallyJava9; | |
39 | ||
36 | 40 | public TryFinally(MethodHandle post) { |
37 | 41 | this.post = post; |
38 | 42 | } |
39 | 43 | |
40 | 44 | public MethodHandle up(MethodHandle target) { |
45 | if (Util.isJava9()) return nativeTryFinally(target, post); | |
46 | ||
41 | 47 | MethodHandle exceptionHandler = Binder |
42 | 48 | .from(target.type().insertParameterTypes(0, Throwable.class).changeReturnType(void.class)) |
43 | 49 | .drop(0) |
71 | 77 | return MethodHandles.foldArguments(realPost, target); |
72 | 78 | } |
73 | 79 | |
80 | private MethodHandle nativeTryFinally(MethodHandle target, MethodHandle post) { | |
81 | MethodType targetType = target.type(); | |
82 | boolean voidReturn = targetType.returnType() == Void.TYPE; | |
83 | MethodType finallyType = targetType.insertParameterTypes(0, Throwable.class); | |
84 | int dropCount = 1; | |
85 | ||
86 | if (!voidReturn) { | |
87 | finallyType = finallyType.insertParameterTypes(1, targetType.returnType()); | |
88 | dropCount = 2; | |
89 | } | |
90 | ||
91 | MethodHandle wrapPost = Binder | |
92 | .from(finallyType) | |
93 | .drop(0, dropCount) | |
94 | .invoke(post); | |
95 | ||
96 | if (!voidReturn) { | |
97 | wrapPost = Binder.from(finallyType) | |
98 | .foldVoid(wrapPost) | |
99 | .permute(1) | |
100 | .identity(); | |
101 | } | |
102 | ||
103 | try { | |
104 | return (MethodHandle) tryFinallyJava9.invokeExact(target, wrapPost); | |
105 | } catch (Throwable t) { | |
106 | throw new RuntimeException("Java 9 detected but MethodHandles.tryFinally missing", t); | |
107 | } | |
108 | } | |
109 | ||
74 | 110 | public MethodType down(MethodType type) { |
75 | 111 | return type; |
76 | 112 | } |
78 | 114 | public String toString() { |
79 | 115 | return "try/finally with " + post; |
80 | 116 | } |
117 | ||
118 | public String toJava(MethodType incoming) { | |
119 | throw new RuntimeException("TryFinally does not yet support toJava"); | |
120 | } | |
121 | ||
122 | static { | |
123 | if (Util.isJava9()) { | |
124 | tryFinallyJava9 = Binder.from(MethodHandle.class, MethodHandle.class, MethodHandle.class).invokeStaticQuiet(MethodHandles.lookup(), MethodHandles.class, "tryFinally"); | |
125 | } else { | |
126 | tryFinallyJava9 = null; | |
127 | } | |
128 | } | |
81 | 129 | } |
58 | 58 | public String toString() { |
59 | 59 | return "varargs at " + index + " into " + arrayType.getName(); |
60 | 60 | } |
61 | ||
62 | public String toJava(MethodType incoming) { | |
63 | StringBuilder builder = new StringBuilder("handle = handle.asVarargsCollector("); | |
64 | ||
65 | buildClassArgument(builder, arrayType); | |
66 | builder.append(").asType("); | |
67 | builder.append(generateMethodType(source)); | |
68 | builder.append(");"); | |
69 | ||
70 | return builder.toString(); | |
71 | } | |
61 | 72 | } |
0 | module com.headius.invokebinder { | |
1 | requires java.base; | |
2 | requires java.logging; | |
3 | ||
4 | exports com.headius.invokebinder; | |
5 | }⏎ |
0 | 0 | package com.headius.invokebinder; |
1 | 1 | |
2 | 2 | import org.junit.Test; |
3 | ||
4 | import static java.lang.invoke.MethodType.methodType; | |
3 | 5 | import static org.junit.Assert.*; |
4 | 6 | |
5 | 7 | import java.io.ByteArrayOutputStream; |
7 | 9 | import java.lang.invoke.MethodHandle; |
8 | 10 | import java.lang.invoke.MethodHandles; |
9 | 11 | import java.lang.invoke.MethodHandles.Lookup; |
10 | import java.lang.invoke.MethodType; | |
12 | import java.lang.invoke.VarHandle; | |
11 | 13 | import java.lang.reflect.Method; |
12 | 14 | |
13 | 15 | /** |
15 | 17 | */ |
16 | 18 | public class BinderTest { |
17 | 19 | private static final Lookup LOOKUP = MethodHandles.lookup(); |
20 | ||
18 | 21 | @Test |
19 | 22 | public void testFrom() throws Throwable { |
20 | 23 | MethodHandle target = Subjects.concatHandle(); |
28 | 31 | .insert(1, "world") |
29 | 32 | .invoke(target); |
30 | 33 | |
31 | assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type()); | |
34 | assertEquals(methodType(String.class, String.class, Object.class), handle.type()); | |
32 | 35 | assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object())); |
33 | 36 | } |
34 | 37 | |
37 | 40 | Binder b1 = Binder |
38 | 41 | .from(void.class) |
39 | 42 | .insert(0, true); |
40 | assertEquals(MethodType.methodType(void.class, boolean.class), b1.type()); | |
43 | assertEquals(methodType(void.class, boolean.class), b1.type()); | |
41 | 44 | Binder b2 = Binder |
42 | 45 | .from(void.class) |
43 | 46 | .insert(0, (byte)1); |
44 | assertEquals(MethodType.methodType(void.class, byte.class), b2.type()); | |
47 | assertEquals(methodType(void.class, byte.class), b2.type()); | |
45 | 48 | Binder b3 = Binder |
46 | 49 | .from(void.class) |
47 | 50 | .insert(0, (short)1); |
48 | assertEquals(MethodType.methodType(void.class, short.class), b3.type()); | |
51 | assertEquals(methodType(void.class, short.class), b3.type()); | |
49 | 52 | Binder b4 = Binder |
50 | 53 | .from(void.class) |
51 | 54 | .insert(0, (char)1); |
52 | assertEquals(MethodType.methodType(void.class, char.class), b4.type()); | |
55 | assertEquals(methodType(void.class, char.class), b4.type()); | |
53 | 56 | Binder b5 = Binder |
54 | 57 | .from(void.class) |
55 | 58 | .insert(0, 1); |
56 | assertEquals(MethodType.methodType(void.class, int.class), b5.type()); | |
59 | assertEquals(methodType(void.class, int.class), b5.type()); | |
57 | 60 | Binder b6 = Binder |
58 | 61 | .from(void.class) |
59 | 62 | .insert(0, 1L); |
60 | assertEquals(MethodType.methodType(void.class, long.class), b6.type()); | |
63 | assertEquals(methodType(void.class, long.class), b6.type()); | |
61 | 64 | Binder b7 = Binder |
62 | 65 | .from(void.class) |
63 | 66 | .insert(0, 1.0F); |
64 | assertEquals(MethodType.methodType(void.class, float.class), b7.type()); | |
67 | assertEquals(methodType(void.class, float.class), b7.type()); | |
65 | 68 | Binder b8 = Binder |
66 | 69 | .from(void.class) |
67 | 70 | .insert(0, 1.0); |
68 | assertEquals(MethodType.methodType(void.class, double.class), b8.type()); | |
71 | assertEquals(methodType(void.class, double.class), b8.type()); | |
69 | 72 | |
70 | 73 | MethodHandle target = intLongHandle(); |
71 | 74 | |
74 | 77 | .insert(0, new Class[]{int.class, long.class}, 1, 1L) |
75 | 78 | .invoke(target); |
76 | 79 | |
77 | assertEquals(MethodType.methodType(String.class), handle.type()); | |
80 | assertEquals(methodType(String.class), handle.type()); | |
78 | 81 | assertEquals("intLong ok", (String) handle.invokeExact()); |
79 | 82 | } |
80 | 83 | |
92 | 95 | |
93 | 96 | Binder newBinder = thisBinder.to(otherBinder); |
94 | 97 | |
95 | assertEquals(MethodType.methodType(String.class, String.class, String.class), otherBinder.type()); | |
96 | assertEquals(MethodType.methodType(String.class, String.class, int.class), thisBinder.type()); | |
97 | assertEquals(MethodType.methodType(String.class, String.class, String.class), newBinder.type()); | |
98 | assertEquals(methodType(String.class, String.class, String.class), otherBinder.type()); | |
99 | assertEquals(methodType(String.class, String.class, int.class), thisBinder.type()); | |
100 | assertEquals(methodType(String.class, String.class, String.class), newBinder.type()); | |
98 | 101 | |
99 | 102 | MethodHandle target = newBinder.invoke(Subjects.concatHandle()); |
100 | 103 | |
106 | 109 | Binder binder = Binder |
107 | 110 | .from(String.class, String.class, Integer.class); |
108 | 111 | |
109 | assertEquals(MethodType.methodType(String.class, String.class, Integer.class), binder.type()); | |
112 | assertEquals(methodType(String.class, String.class, Integer.class), binder.type()); | |
110 | 113 | |
111 | 114 | binder = binder |
112 | 115 | .drop(1); |
113 | 116 | |
114 | assertEquals(MethodType.methodType(String.class, String.class), binder.type()); | |
117 | assertEquals(methodType(String.class, String.class), binder.type()); | |
115 | 118 | } |
116 | 119 | |
117 | 120 | @Test |
141 | 144 | .insert(1, "world") |
142 | 145 | .invoke(target); |
143 | 146 | |
144 | assertEquals(MethodType.methodType(String.class, String.class), handle.type()); | |
147 | assertEquals(methodType(String.class, String.class), handle.type()); | |
145 | 148 | assertEquals("Hello, world", (String) handle.invokeExact("Hello, ")); |
146 | 149 | |
147 | 150 | MethodHandle target2 = Subjects.concatCharSequenceHandle(); |
150 | 153 | .insert(1, CharSequence.class, "world") |
151 | 154 | .invoke(target2); |
152 | 155 | |
153 | assertEquals(MethodType.methodType(String.class, String.class), handle2.type()); | |
156 | assertEquals(methodType(String.class, String.class), handle2.type()); | |
154 | 157 | assertEquals("Hello, world", (String) handle2.invokeExact("Hello, ")); |
155 | 158 | } |
156 | 159 | |
163 | 166 | .drop(1) |
164 | 167 | .invoke(target); |
165 | 168 | |
166 | assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type()); | |
169 | assertEquals(methodType(String.class, String.class, Object.class), handle.type()); | |
167 | 170 | assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object())); |
168 | 171 | |
169 | 172 | MethodHandle target2 = Subjects.concatCharSequenceHandle(); |
173 | 176 | .drop(1) |
174 | 177 | .invoke(target2); |
175 | 178 | |
176 | assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle2.type()); | |
179 | assertEquals(methodType(String.class, String.class, Object.class), handle2.type()); | |
177 | 180 | assertEquals("Hello, world", (String) handle2.invokeExact("Hello, ", new Object())); |
178 | 181 | } |
179 | 182 | |
186 | 189 | .drop(1) |
187 | 190 | .invoke(target); |
188 | 191 | |
189 | assertEquals(MethodType.methodType(String.class, Object.class, String.class), handle.type()); | |
192 | assertEquals(methodType(String.class, Object.class, String.class), handle.type()); | |
190 | 193 | assertEquals("Hello, world", (String) handle.invokeExact(new Object(), "world")); |
191 | 194 | |
192 | 195 | MethodHandle target2 = Subjects.concatHandle(); |
196 | 199 | .drop(1) |
197 | 200 | .invoke(target2); |
198 | 201 | |
199 | assertEquals(MethodType.methodType(String.class, Object.class, String.class), handle2.type()); | |
202 | assertEquals(methodType(String.class, Object.class, String.class), handle2.type()); | |
200 | 203 | assertEquals("Hello, world", (String) handle2.invokeExact(new Object(), "world")); |
201 | 204 | } |
202 | 205 | |
209 | 212 | .insert(1, "world") |
210 | 213 | .invoke(target); |
211 | 214 | |
212 | assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type()); | |
215 | assertEquals(methodType(String.class, String.class, Object.class), handle.type()); | |
213 | 216 | assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object())); |
214 | 217 | } |
215 | 218 | |
222 | 225 | .insert(1, "world") |
223 | 226 | .invoke(target); |
224 | 227 | |
225 | assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type()); | |
228 | assertEquals(methodType(String.class, String.class, Object.class), handle.type()); | |
226 | 229 | assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object())); |
227 | 230 | |
228 | 231 | handle = Binder |
231 | 234 | .insert(1, "world") |
232 | 235 | .invoke(target); |
233 | 236 | |
234 | assertEquals(MethodType.methodType(String.class, String.class, Object.class, double.class), handle.type()); | |
237 | assertEquals(methodType(String.class, String.class, Object.class, double.class), handle.type()); | |
235 | 238 | assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object(), 1.0)); |
236 | 239 | } |
237 | 240 | |
244 | 247 | .insert(1, "world") |
245 | 248 | .invoke(target); |
246 | 249 | |
247 | assertEquals(MethodType.methodType(String.class, Object.class, String.class), handle.type()); | |
250 | assertEquals(methodType(String.class, Object.class, String.class), handle.type()); | |
248 | 251 | assertEquals("Hello, world", (String) handle.invokeExact(new Object(), "Hello, ")); |
249 | 252 | |
250 | 253 | handle = Binder |
253 | 256 | .insert(1, "world") |
254 | 257 | .invoke(target); |
255 | 258 | |
256 | assertEquals(MethodType.methodType(String.class, Object.class, double.class, String.class), handle.type()); | |
259 | assertEquals(methodType(String.class, Object.class, double.class, String.class), handle.type()); | |
257 | 260 | assertEquals("Hello, world", (String) handle.invokeExact(new Object(), 1.0, "Hello, ")); |
258 | 261 | } |
259 | 262 | |
266 | 269 | .insert(0, "Hello, ", "world") |
267 | 270 | .invoke(target); |
268 | 271 | |
269 | assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type()); | |
272 | assertEquals(methodType(String.class, String.class, Object.class), handle.type()); | |
270 | 273 | assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object())); |
271 | 274 | } |
272 | 275 | |
278 | 281 | .convert(target.type()) |
279 | 282 | .invoke(target); |
280 | 283 | |
281 | assertEquals(MethodType.methodType(String.class, Object.class, Integer.class, Float.class), handle.type()); | |
284 | assertEquals(methodType(String.class, Object.class, Integer.class, Float.class), handle.type()); | |
282 | 285 | assertEquals(null, (String) handle.invokeExact((Object) "foo", (Integer) 5, (Float) 5.0f)); |
283 | 286 | } |
284 | 287 | |
290 | 293 | .convert(target.type().returnType(), target.type().parameterArray()) |
291 | 294 | .invoke(target); |
292 | 295 | |
293 | assertEquals(MethodType.methodType(String.class, Object.class, Integer.class, Float.class), handle.type()); | |
296 | assertEquals(methodType(String.class, Object.class, Integer.class, Float.class), handle.type()); | |
294 | 297 | assertEquals(null, (String)handle.invokeExact((Object)"foo", (Integer)5, (Float)5.0f)); |
295 | 298 | } |
296 | 299 | |
302 | 305 | .cast(target.type()) |
303 | 306 | .invoke(target); |
304 | 307 | |
305 | assertEquals(MethodType.methodType(String.class, Object.class, byte.class, int.class), handle.type()); | |
308 | assertEquals(methodType(String.class, Object.class, byte.class, int.class), handle.type()); | |
306 | 309 | assertEquals(null, (String)handle.invokeExact((Object)"foo", (byte)5, 5)); |
307 | 310 | } |
308 | 311 | |
314 | 317 | .cast(target.type().returnType(), target.type().parameterArray()) |
315 | 318 | .invoke(target); |
316 | 319 | |
317 | assertEquals(MethodType.methodType(String.class, Object.class, byte.class, int.class), handle.type()); | |
320 | assertEquals(methodType(String.class, Object.class, byte.class, int.class), handle.type()); | |
318 | 321 | assertEquals(null, (String)handle.invokeExact((Object)"foo", (byte)5, 5)); |
319 | 322 | } |
320 | 323 | |
327 | 330 | .permute(0, 0) |
328 | 331 | .invoke(target); |
329 | 332 | |
330 | assertEquals(MethodType.methodType(String.class, Integer.class, Float.class, String.class), handle.type()); | |
333 | assertEquals(methodType(String.class, Integer.class, Float.class, String.class), handle.type()); | |
331 | 334 | assertEquals("foofoo", (String)handle.invokeExact((Integer) 0, (Float) 0.0f, "foo")); |
332 | 335 | } |
333 | 336 | |
339 | 342 | .spread(String.class, String.class) |
340 | 343 | .invoke(target); |
341 | 344 | |
342 | assertEquals(MethodType.methodType(String.class, Object[].class), handle.type()); | |
345 | assertEquals(methodType(String.class, Object[].class), handle.type()); | |
343 | 346 | assertEquals("foobar", (String)handle.invokeExact(new Object[] {"foo", "bar"})); |
344 | 347 | } |
345 | 348 | |
351 | 354 | .spread(2) |
352 | 355 | .invoke(target); |
353 | 356 | |
354 | assertEquals(MethodType.methodType(String.class, String[].class), handle.type()); | |
357 | assertEquals(methodType(String.class, String[].class), handle.type()); | |
355 | 358 | assertEquals("foobar", (String)handle.invokeExact(new String[] {"foo", "bar"})); |
356 | 359 | } |
357 | 360 | |
362 | 365 | .collect(1, String[].class) |
363 | 366 | .invokeStatic(LOOKUP, BinderTest.class, "varargs"); |
364 | 367 | |
365 | assertEquals(MethodType.methodType(String[].class, String.class, String.class, String.class), handle.type()); | |
368 | assertEquals(methodType(String[].class, String.class, String.class, String.class), handle.type()); | |
366 | 369 | String[] ary = (String[])handle.invokeExact("one", "two", "three"); |
367 | 370 | assertEquals(2, ary.length); |
368 | 371 | assertEquals("two", ary[0]); |
373 | 376 | .collect(1, 3, Integer[].class) |
374 | 377 | .invoke(Subjects.StringIntegersStringHandle); |
375 | 378 | |
376 | assertEquals(MethodType.methodType(String.class, String.class, Integer.class, Integer.class, Integer.class, String.class), handle2.type()); | |
379 | assertEquals(methodType(String.class, String.class, Integer.class, Integer.class, Integer.class, String.class), handle2.type()); | |
377 | 380 | assertEquals("[foo, [1, 2, 3], bar]", (String)handle2.invokeExact("foo", new Integer(1), new Integer(2), new Integer(3), "bar")); |
378 | 381 | } |
379 | 382 | |
380 | @Test | |
381 | public void testVarargs() throws Throwable { | |
382 | MethodHandle handle = Binder | |
383 | public static String[] newStringArray(String s1, String s2) { | |
384 | return new String[] {s1, s2}; | |
385 | } | |
386 | ||
387 | public static MethodHandle newStringArrayHandle() throws Exception { | |
388 | return LOOKUP.findStatic(BinderTest.class, "newStringArray", methodType(String[].class, String.class, String.class)); | |
389 | } | |
390 | ||
391 | @Test | |
392 | public void testCollectWithCollector() throws Throwable { | |
393 | Binder binder = Binder | |
383 | 394 | .from(String[].class, String.class, String.class, String.class) |
384 | .varargs(1, String[].class) | |
395 | .collect(1, String[].class, newStringArrayHandle()); | |
396 | ||
397 | String toJava = binder.toJava(methodType(String[].class, String.class, String.class, String.class)); | |
398 | ||
399 | assertTrue(toJava.contains("collectArguments")); | |
400 | ||
401 | MethodHandle handle = binder | |
385 | 402 | .invokeStatic(LOOKUP, BinderTest.class, "varargs"); |
386 | 403 | |
387 | assertEquals(MethodType.methodType(String[].class, String.class, String.class, String.class), handle.type()); | |
404 | assertEquals(methodType(String[].class, String.class, String.class, String.class), handle.type()); | |
388 | 405 | String[] ary = (String[])handle.invokeExact("one", "two", "three"); |
389 | 406 | assertEquals(2, ary.length); |
390 | 407 | assertEquals("two", ary[0]); |
391 | 408 | assertEquals("three", ary[1]); |
409 | } | |
410 | ||
411 | @Test | |
412 | public void testVarargs() throws Throwable { | |
413 | MethodHandle handle = Binder | |
414 | .from(String[].class, String.class, String.class, String.class) | |
415 | .varargs(1, String[].class) | |
416 | .invokeStatic(LOOKUP, BinderTest.class, "varargs"); | |
417 | ||
418 | assertEquals(methodType(String[].class, String.class, String.class, String.class), handle.type()); | |
419 | String[] ary = (String[])handle.invokeExact("one", "two", "three"); | |
420 | assertEquals(2, ary.length); | |
421 | assertEquals("two", ary[0]); | |
422 | assertEquals("three", ary[1]); | |
392 | 423 | |
393 | 424 | // from #2 |
394 | MethodHandle foo = Binder.from(MethodType.methodType(String.class, String.class)) | |
425 | MethodHandle foo = Binder.from(methodType(String.class, String.class)) | |
395 | 426 | .varargs(0, Object[].class) |
396 | 427 | .invokeStatic(MethodHandles.publicLookup(), getClass(), "varargs"); |
397 | 428 | |
404 | 435 | .from(String.class) |
405 | 436 | .constant("hello"); |
406 | 437 | |
407 | assertEquals(MethodType.methodType(String.class), handle.type()); | |
438 | assertEquals(methodType(String.class), handle.type()); | |
408 | 439 | assertEquals("hello", (String)handle.invokeExact()); |
409 | 440 | } |
410 | 441 | |
414 | 445 | .from(Object.class) |
415 | 446 | .constant("hello"); |
416 | 447 | |
417 | assertEquals(MethodType.methodType(Object.class), handle.type()); | |
448 | assertEquals(methodType(Object.class), handle.type()); | |
418 | 449 | assertEquals("hello", (Object)handle.invokeExact()); |
419 | 450 | } |
420 | 451 | |
424 | 455 | .from(String.class, String.class) |
425 | 456 | .identity(); |
426 | 457 | |
427 | assertEquals(MethodType.methodType(String.class, String.class), handle.type()); | |
458 | assertEquals(methodType(String.class, String.class), handle.type()); | |
428 | 459 | assertEquals("hello", (String)handle.invokeExact("hello")); |
429 | 460 | } |
430 | 461 | |
440 | 471 | .fold(fold) |
441 | 472 | .invoke(target); |
442 | 473 | |
443 | assertEquals(MethodType.methodType(String.class, String.class), handle.type()); | |
474 | assertEquals(methodType(String.class, String.class), handle.type()); | |
444 | 475 | assertEquals("yahoofoo", (String)handle.invokeExact("foo")); |
445 | 476 | } |
446 | 477 | |
452 | 483 | .foldStatic(BinderTest.class, "alwaysYahooStatic") |
453 | 484 | .invoke(target); |
454 | 485 | |
455 | assertEquals(MethodType.methodType(String.class, String.class), handle.type()); | |
486 | assertEquals(methodType(String.class, String.class), handle.type()); | |
456 | 487 | assertEquals("yahoofoo", (String)handle.invokeExact("foo")); |
457 | 488 | } |
458 | 489 | |
466 | 497 | .drop(1) |
467 | 498 | .invoke(target); |
468 | 499 | |
469 | assertEquals(MethodType.methodType(String.class, String.class), handle.type()); | |
500 | assertEquals(methodType(String.class, String.class), handle.type()); | |
470 | 501 | assertEquals("yahoofoo", (String)handle.invokeExact("foo")); |
471 | 502 | } |
472 | 503 | |
473 | 504 | @Test |
474 | 505 | public void testFilter() throws Throwable { |
475 | 506 | MethodHandle target = Subjects.concatHandle(); |
476 | MethodHandle filter = LOOKUP.findStatic(BinderTest.class, "addBaz", MethodType.methodType(String.class, String.class)); | |
507 | MethodHandle filter = LOOKUP.findStatic(BinderTest.class, "addBaz", methodType(String.class, String.class)); | |
477 | 508 | MethodHandle handle = Binder |
478 | 509 | .from(String.class, String.class, String.class) |
479 | 510 | .filter(0, filter, filter) |
480 | 511 | .invoke(target); |
481 | 512 | |
482 | assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type()); | |
513 | assertEquals(methodType(String.class, String.class, String.class), handle.type()); | |
483 | 514 | assertEquals("foobazbarbaz", (String)handle.invokeExact("foo", "bar")); |
484 | 515 | } |
485 | 516 | |
486 | 517 | @Test |
518 | public void testFilterForward() throws Throwable { | |
519 | MethodHandle target = LOOKUP.findStatic(Subjects.class, "twoIntsToString", methodType(String.class, int.class, int.class)); | |
520 | MethodHandle[] filters = {Subjects.nextInt, Subjects.nextInt}; | |
521 | MethodHandle handle = Binder.from(String.class, int.class, int.class) | |
522 | .filterForward(0, filters) | |
523 | .invoke(target); | |
524 | ||
525 | int first = Subjects.counter.get(); | |
526 | ||
527 | assertEquals("(" + first + ", " + (first + 1) + ")", (String) handle.invokeExact(0, 0)); | |
528 | } | |
529 | ||
530 | @Test | |
487 | 531 | public void testInvoke() throws Throwable { |
488 | 532 | MethodHandle target = Subjects.concatHandle(); |
489 | 533 | MethodHandle handle = Binder |
490 | 534 | .from(String.class, String.class, String.class) |
491 | 535 | .invoke(target); |
492 | 536 | |
493 | assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type()); | |
537 | assertEquals(methodType(String.class, String.class, String.class), handle.type()); | |
494 | 538 | assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world")); |
495 | 539 | } |
496 | 540 | |
501 | 545 | .from(String.class, String.class, String.class) |
502 | 546 | .invoke(LOOKUP, target); |
503 | 547 | |
504 | assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type()); | |
548 | assertEquals(methodType(String.class, String.class, String.class), handle.type()); | |
505 | 549 | assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world")); |
506 | 550 | } |
507 | 551 | |
512 | 556 | .from(String.class, String.class, String.class) |
513 | 557 | .invokeQuiet(LOOKUP, target); |
514 | 558 | |
515 | assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type()); | |
559 | assertEquals(methodType(String.class, String.class, String.class), handle.type()); | |
516 | 560 | assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world")); |
517 | 561 | } |
518 | 562 | |
522 | 566 | .from(String.class, String.class, String.class) |
523 | 567 | .invokeStatic(LOOKUP, Subjects.class, "concatStatic"); |
524 | 568 | |
525 | assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type()); | |
569 | assertEquals(methodType(String.class, String.class, String.class), handle.type()); | |
526 | 570 | assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world")); |
527 | 571 | } |
528 | 572 | |
532 | 576 | .from(String.class, String.class, String.class) |
533 | 577 | .invokeStaticQuiet(LOOKUP, Subjects.class, "concatStatic"); |
534 | 578 | |
535 | assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type()); | |
579 | assertEquals(methodType(String.class, String.class, String.class), handle.type()); | |
536 | 580 | assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world")); |
537 | 581 | } |
538 | 582 | |
542 | 586 | .from(String.class, BinderTest.class, String.class, String.class) |
543 | 587 | .invokeVirtual(LOOKUP, "concatVirtual"); |
544 | 588 | |
545 | assertEquals(MethodType.methodType(String.class, BinderTest.class, String.class, String.class), handle.type()); | |
589 | assertEquals(methodType(String.class, BinderTest.class, String.class, String.class), handle.type()); | |
546 | 590 | assertEquals("Hello, world", (String) handle.invokeExact(this, "Hello, ", "world")); |
547 | 591 | } |
548 | 592 | |
552 | 596 | .from(String.class, BinderTest.class, String.class, String.class) |
553 | 597 | .invokeVirtualQuiet(LOOKUP, "concatVirtual"); |
554 | 598 | |
555 | assertEquals(MethodType.methodType(String.class, BinderTest.class, String.class, String.class), handle.type()); | |
599 | assertEquals(methodType(String.class, BinderTest.class, String.class, String.class), handle.type()); | |
556 | 600 | assertEquals("Hello, world", (String) handle.invokeExact(this, "Hello, ", "world")); |
557 | 601 | } |
558 | 602 | |
562 | 606 | .from(Constructable.class, String.class, String.class) |
563 | 607 | .invokeConstructor(LOOKUP, Constructable.class); |
564 | 608 | |
565 | assertEquals(MethodType.methodType(Constructable.class, String.class, String.class), handle.type()); | |
609 | assertEquals(methodType(Constructable.class, String.class, String.class), handle.type()); | |
566 | 610 | assertEquals(new Constructable("foo", "bar"), (Constructable) handle.invokeExact("foo", "bar")); |
567 | 611 | } |
568 | 612 | |
572 | 616 | .from(Constructable.class, String.class, String.class) |
573 | 617 | .invokeConstructorQuiet(LOOKUP, Constructable.class); |
574 | 618 | |
575 | assertEquals(MethodType.methodType(Constructable.class, String.class, String.class), handle.type()); | |
619 | assertEquals(methodType(Constructable.class, String.class, String.class), handle.type()); | |
576 | 620 | assertEquals(new Constructable("foo", "bar"), (Constructable) handle.invokeExact("foo", "bar")); |
577 | 621 | } |
578 | 622 | |
583 | 627 | .from(String.class, Fields.class) |
584 | 628 | .getField(LOOKUP, "instanceField"); |
585 | 629 | |
586 | assertEquals(MethodType.methodType(String.class, Fields.class), handle.type()); | |
630 | assertEquals(methodType(String.class, Fields.class), handle.type()); | |
587 | 631 | assertEquals("initial", (String)handle.invokeExact(fields)); |
588 | 632 | } |
589 | 633 | |
594 | 638 | .from(String.class, Fields.class) |
595 | 639 | .getFieldQuiet(LOOKUP, "instanceField"); |
596 | 640 | |
597 | assertEquals(MethodType.methodType(String.class, Fields.class), handle.type()); | |
641 | assertEquals(methodType(String.class, Fields.class), handle.type()); | |
598 | 642 | assertEquals("initial", (String)handle.invokeExact(fields)); |
599 | 643 | } |
600 | 644 | |
604 | 648 | .from(String.class) |
605 | 649 | .getStatic(LOOKUP, Fields.class, "staticField"); |
606 | 650 | |
607 | assertEquals(MethodType.methodType(String.class), handle.type()); | |
651 | assertEquals(methodType(String.class), handle.type()); | |
608 | 652 | assertEquals("initial", (String)handle.invokeExact()); |
609 | 653 | } |
610 | 654 | |
614 | 658 | .from(String.class) |
615 | 659 | .getStaticQuiet(LOOKUP, Fields.class, "staticField"); |
616 | 660 | |
617 | assertEquals(MethodType.methodType(String.class), handle.type()); | |
661 | assertEquals(methodType(String.class), handle.type()); | |
618 | 662 | assertEquals("initial", (String)handle.invokeExact()); |
619 | 663 | } |
620 | 664 | |
625 | 669 | .from(void.class, Fields.class, String.class) |
626 | 670 | .setField(LOOKUP, "instanceField"); |
627 | 671 | |
628 | assertEquals(MethodType.methodType(void.class, Fields.class, String.class), handle.type()); | |
672 | assertEquals(methodType(void.class, Fields.class, String.class), handle.type()); | |
629 | 673 | handle.invokeExact(fields, "modified"); |
630 | 674 | assertEquals("modified", fields.instanceField); |
631 | 675 | } |
637 | 681 | .from(void.class, Fields.class, String.class) |
638 | 682 | .setFieldQuiet(LOOKUP, "instanceField"); |
639 | 683 | |
640 | assertEquals(MethodType.methodType(void.class, Fields.class, String.class), handle.type()); | |
684 | assertEquals(methodType(void.class, Fields.class, String.class), handle.type()); | |
641 | 685 | handle.invokeExact(fields, "modified"); |
642 | 686 | assertEquals("modified", fields.instanceField); |
643 | 687 | } |
649 | 693 | .from(void.class, String.class) |
650 | 694 | .setStatic(LOOKUP, Fields.class, "staticField"); |
651 | 695 | |
652 | assertEquals(MethodType.methodType(void.class, String.class), handle.type()); | |
696 | assertEquals(methodType(void.class, String.class), handle.type()); | |
653 | 697 | handle.invokeExact("modified"); |
654 | 698 | assertEquals("modified", Fields.staticField); |
655 | 699 | } finally { |
664 | 708 | .from(void.class, String.class) |
665 | 709 | .setStaticQuiet(LOOKUP, Fields.class, "staticField"); |
666 | 710 | |
667 | assertEquals(MethodType.methodType(void.class, String.class), handle.type()); | |
711 | assertEquals(methodType(void.class, String.class), handle.type()); | |
668 | 712 | handle.invokeExact("modified"); |
669 | 713 | assertEquals("modified", Fields.staticField); |
670 | 714 | } finally { |
678 | 722 | .from(void.class, int.class, String.class) |
679 | 723 | .nop(); |
680 | 724 | |
681 | assertEquals(MethodType.methodType(void.class, int.class, String.class), handle.type()); | |
725 | assertEquals(methodType(void.class, int.class, String.class), handle.type()); | |
682 | 726 | try { |
683 | 727 | handle.invokeExact(1, "foo"); |
684 | 728 | } catch (Throwable t) { |
692 | 736 | .from(void.class, BlahException.class) |
693 | 737 | .throwException(); |
694 | 738 | |
695 | assertEquals(MethodType.methodType(void.class, BlahException.class), handle.type()); | |
739 | assertEquals(methodType(void.class, BlahException.class), handle.type()); | |
696 | 740 | try { |
697 | 741 | handle.invokeExact(new BlahException()); |
698 | 742 | assertTrue("should not reach here", false); |
711 | 755 | .tryFinally(post) |
712 | 756 | .invokeStatic(LOOKUP, BinderTest.class, "setZeroToFoo"); |
713 | 757 | |
714 | assertEquals(MethodType.methodType(void.class, String[].class), handle.type()); | |
758 | assertEquals(methodType(void.class, String[].class), handle.type()); | |
715 | 759 | String[] stringAry = new String[1]; |
716 | 760 | handle.invokeExact(stringAry); |
717 | 761 | assertEquals("foofinally", stringAry[0]); |
728 | 772 | .tryFinally(post) |
729 | 773 | .invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooAndRaise"); |
730 | 774 | |
731 | assertEquals(MethodType.methodType(void.class, String[].class), handle.type()); | |
775 | assertEquals(methodType(void.class, String[].class), handle.type()); | |
732 | 776 | String[] stringAry = new String[1]; |
733 | 777 | try { |
734 | 778 | handle.invokeExact(stringAry); |
754 | 798 | .catchException(BlahException.class, ignoreException) |
755 | 799 | .invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooAndRaise"); |
756 | 800 | |
757 | assertEquals(MethodType.methodType(void.class, String[].class), handle.type()); | |
801 | assertEquals(methodType(void.class, String[].class), handle.type()); | |
758 | 802 | String[] stringAry = new String[1]; |
759 | 803 | try { |
760 | 804 | handle.invokeExact(stringAry); |
775 | 819 | .tryFinally(post) |
776 | 820 | .invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooReturnInt"); |
777 | 821 | |
778 | assertEquals(MethodType.methodType(int.class, String[].class), handle.type()); | |
822 | assertEquals(methodType(int.class, String[].class), handle.type()); | |
779 | 823 | String[] stringAry = new String[1]; |
780 | 824 | assertEquals(1, (int)handle.invokeExact(stringAry)); |
781 | 825 | assertEquals("foofinally", stringAry[0]); |
792 | 836 | .tryFinally(post) |
793 | 837 | .invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooReturnIntAndRaise"); |
794 | 838 | |
795 | assertEquals(MethodType.methodType(int.class, String[].class), handle.type()); | |
839 | assertEquals(methodType(int.class, String[].class), handle.type()); | |
796 | 840 | String[] stringAry = new String[1]; |
797 | 841 | try { |
798 | 842 | int x = (int)handle.invokeExact(stringAry); |
819 | 863 | .catchException(BlahException.class, ignoreException) |
820 | 864 | .invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooReturnIntAndRaise"); |
821 | 865 | |
822 | assertEquals(MethodType.methodType(int.class, String[].class), handle.type()); | |
866 | assertEquals(methodType(int.class, String[].class), handle.type()); | |
823 | 867 | String[] stringAry = new String[1]; |
824 | 868 | try { |
825 | 869 | assertEquals(1, (int)handle.invokeExact(stringAry)); |
835 | 879 | .from(void.class, Object[].class, int.class, Object.class) |
836 | 880 | .arraySet(); |
837 | 881 | |
838 | assertEquals(MethodType.methodType(void.class, Object[].class, int.class, Object.class), handle.type()); | |
882 | assertEquals(methodType(void.class, Object[].class, int.class, Object.class), handle.type()); | |
839 | 883 | Object[] ary = new Object[1]; |
840 | 884 | handle.invokeExact(ary, 0, (Object)"foo"); |
841 | 885 | assertEquals(ary[0], "foo"); |
847 | 891 | .from(Object.class, Object[].class, int.class) |
848 | 892 | .arrayGet(); |
849 | 893 | |
850 | assertEquals(MethodType.methodType(Object.class, Object[].class, int.class), handle.type()); | |
894 | assertEquals(methodType(Object.class, Object[].class, int.class), handle.type()); | |
851 | 895 | Object[] ary = new Object[] {"foo"}; |
852 | 896 | assertEquals(handle.invokeExact(ary, 0), "foo"); |
897 | } | |
898 | ||
899 | public static final VarHandle.AccessMode[] GET_ACCESS_MODES = new VarHandle.AccessMode[]{ | |
900 | VarHandle.AccessMode.GET, | |
901 | VarHandle.AccessMode.GET_VOLATILE, | |
902 | VarHandle.AccessMode.GET_ACQUIRE, | |
903 | VarHandle.AccessMode.GET_OPAQUE}; | |
904 | ||
905 | public static final VarHandle.AccessMode[] SET_ACCESS_MODES = new VarHandle.AccessMode[]{ | |
906 | VarHandle.AccessMode.SET, | |
907 | VarHandle.AccessMode.SET_VOLATILE, | |
908 | VarHandle.AccessMode.SET_RELEASE, | |
909 | VarHandle.AccessMode.SET_OPAQUE}; | |
910 | ||
911 | @Test | |
912 | public void testArrayAccess() throws Throwable { | |
913 | for (VarHandle.AccessMode mode : GET_ACCESS_MODES) { | |
914 | MethodHandle handle = Binder | |
915 | .from(Object.class, Object[].class, int.class) | |
916 | .arrayAccess(mode); | |
917 | ||
918 | assertEquals(methodType(Object.class, Object[].class, int.class), handle.type()); | |
919 | Object[] ary = new Object[]{"foo"}; | |
920 | assertEquals(handle.invokeExact(ary, 0), "foo"); | |
921 | } | |
922 | ||
923 | for (VarHandle.AccessMode mode : SET_ACCESS_MODES) { | |
924 | MethodHandle handle = Binder | |
925 | .from(void.class, Object[].class, int.class, Object.class) | |
926 | .arrayAccess(mode); | |
927 | ||
928 | assertEquals(methodType(void.class, Object[].class, int.class, Object.class), handle.type()); | |
929 | Object[] ary = new Object[1]; | |
930 | handle.invokeExact(ary, 0, (Object) "foo"); | |
931 | assertEquals(ary[0], "foo"); | |
932 | } | |
853 | 933 | } |
854 | 934 | |
855 | 935 | @Test |
868 | 948 | .invokeStatic(LOOKUP, BinderTest.class, "addBaz") |
869 | 949 | ); |
870 | 950 | |
871 | assertEquals(MethodType.methodType(String.class, String.class), handle.type()); | |
951 | assertEquals(methodType(String.class, String.class), handle.type()); | |
872 | 952 | assertEquals("foobar", (String)handle.invokeExact("foo")); |
873 | 953 | assertEquals("quuxbaz", (String)handle.invokeExact("quux")); |
874 | 954 | } |
876 | 956 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
877 | 957 | |
878 | 958 | public static MethodHandle intLongHandle() throws Exception { |
879 | return LOOKUP.findStatic(BinderTest.class, "intLong", MethodType.methodType(String.class, int.class, long.class)); | |
959 | return LOOKUP.findStatic(BinderTest.class, "intLong", methodType(String.class, int.class, long.class)); | |
880 | 960 | } |
881 | 961 | |
882 | 962 | public String concatVirtual(String a, String b) { |
956 | 1036 | } |
957 | 1037 | |
958 | 1038 | public static MethodHandle mixedHandle() throws Exception { |
959 | return LOOKUP.findStatic(BinderTest.class, "mixed", MethodType.methodType(void.class, String.class, int.class, float.class)); | |
1039 | return LOOKUP.findStatic(BinderTest.class, "mixed", methodType(void.class, String.class, int.class, float.class)); | |
960 | 1040 | } |
961 | 1041 | |
962 | 1042 | public static void mixed(String a, int b, float c) { |
3 | 3 | import java.lang.invoke.MethodHandles; |
4 | 4 | import java.lang.invoke.MethodType; |
5 | 5 | import java.util.Arrays; |
6 | import java.util.concurrent.atomic.AtomicInteger; | |
6 | 7 | |
7 | 8 | /** |
8 | 9 | * Created by headius on 1/25/14. |
79 | 80 | public static String upperCase(String x) { |
80 | 81 | return x.toUpperCase(); |
81 | 82 | } |
83 | ||
84 | public static String twoIntsToString(int a, int b) { | |
85 | return "(" + a + ", " + b + ")"; | |
86 | } | |
87 | ||
88 | public static int nextInt(int ignored) { | |
89 | return counter.getAndIncrement(); | |
90 | } | |
91 | ||
92 | public static MethodHandle nextInt = Binder.from(int.class, int.class).invokeStaticQuiet(LOOKUP, Subjects.class, "nextInt"); | |
93 | ||
94 | public static final AtomicInteger counter = new AtomicInteger(0); | |
82 | 95 | |
83 | 96 | } |
0 | package com.headius.invokebinder; | |
1 | ||
2 | import com.headius.invokebinder.transform.Cast; | |
3 | import com.headius.invokebinder.transform.Catch; | |
4 | import com.headius.invokebinder.transform.Collect; | |
5 | import com.headius.invokebinder.transform.Convert; | |
6 | import com.headius.invokebinder.transform.Drop; | |
7 | import com.headius.invokebinder.transform.Filter; | |
8 | import com.headius.invokebinder.transform.FilterReturn; | |
9 | import com.headius.invokebinder.transform.Fold; | |
10 | import com.headius.invokebinder.transform.Insert; | |
11 | import com.headius.invokebinder.transform.Spread; | |
12 | import com.headius.invokebinder.transform.Transform; | |
13 | import com.headius.invokebinder.transform.Varargs; | |
14 | import org.junit.Assert; | |
15 | import org.junit.Test; | |
16 | ||
17 | import java.lang.invoke.MethodHandle; | |
18 | import java.lang.invoke.MethodHandles; | |
19 | import java.lang.invoke.MethodType; | |
20 | ||
21 | public class ToJavaTest { | |
22 | @Test | |
23 | public void testCast() { | |
24 | Cast cast = new Cast(MethodType.methodType(String.class, Integer[].class, float.class)); | |
25 | ||
26 | String toJava = cast.toJava(null); | |
27 | ||
28 | Assert.assertEquals("handle = MethodHandles.explicitCastArguments(handle, java.lang.Integer[].class, float.class);", toJava); | |
29 | } | |
30 | ||
31 | @Test | |
32 | public void testCatch() { | |
33 | Catch ctch = new Catch(RuntimeException.class, DUMMY_HANDLE); | |
34 | ||
35 | String toJava = ctch.toJava(null); | |
36 | ||
37 | Assert.assertEquals("handle = MethodHandles.catchException(handle, java.lang.RuntimeException.class, " + Catch.EXCEPTION_HANDLER_JAVA + ");", toJava); | |
38 | } | |
39 | ||
40 | @Test | |
41 | public void testCollect() { | |
42 | MethodType source = MethodType.methodType(void.class, int.class, int.class, int.class); | |
43 | MethodType incoming = MethodType.methodType(void.class, int.class, int[].class); | |
44 | ||
45 | Collect collect = new Collect(source, 1, int[].class); | |
46 | ||
47 | String toJava = collect.toJava(incoming); | |
48 | ||
49 | Assert.assertEquals("handle = handle.asCollector(int[].class, 2);", toJava); | |
50 | ||
51 | collect = new Collect(source, 1, 1, int[].class); | |
52 | ||
53 | toJava = collect.toJava(incoming); | |
54 | ||
55 | String expected = | |
56 | "handle = MethodHandles.permuteArguments(handle, MethodType.methodType(void.class, int.class, int.class, int[].class), new int[] {0, 1});\n" + | |
57 | "handle = handle.asCollector(int[].class, 1);\n" + | |
58 | "handle = MethodHandles.permuteArguments(handle, MethodType.methodType(void.class, int.class, int.class, int.class), new int[] {0, 2, 1});"; | |
59 | ||
60 | Assert.assertEquals(expected, toJava); | |
61 | } | |
62 | ||
63 | @Test | |
64 | public void testConvert() { | |
65 | MethodType source = MethodType.methodType(void.class, String.class); | |
66 | MethodType incoming = MethodType.methodType(void.class, Object.class); | |
67 | ||
68 | Convert convert = new Convert(source); | |
69 | ||
70 | String toJava = convert.toJava(incoming); | |
71 | ||
72 | String expected = "handle = MethodHandles.explicitCastArguments(handle.asType(MethodType.methodType(void.class, java.lang.String.class), MethodType.methodType(void.class, java.lang.String.class));"; | |
73 | ||
74 | Assert.assertEquals(expected, toJava); | |
75 | ||
76 | source = MethodType.methodType(long.class, String.class); | |
77 | incoming = MethodType.methodType(int.class, Object.class); | |
78 | ||
79 | convert = new Convert(source); | |
80 | ||
81 | toJava = convert.toJava(incoming); | |
82 | ||
83 | Assert.assertEquals("handle = handle.asType(MethodType.methodType(long.class, java.lang.String.class));", toJava); | |
84 | } | |
85 | ||
86 | @Test | |
87 | public void testDrop() { | |
88 | MethodType incoming = MethodType.methodType(void.class); | |
89 | ||
90 | Drop drop = new Drop(0, int.class, int.class, int.class); | |
91 | ||
92 | String toJava = drop.toJava(incoming); | |
93 | ||
94 | Assert.assertEquals("handle = MethodHandles.dropArguments(handle, 0, int.class, int.class, int.class);", toJava); | |
95 | } | |
96 | ||
97 | @Test | |
98 | public void testFilter() { | |
99 | Filter filter = new Filter(0, null); | |
100 | ||
101 | String toJava = filter.toJava(DUMMY_HANDLE.type()); | |
102 | ||
103 | Assert.assertEquals("handle = MethodHandles.filterArguments(handle, 0, " + Filter.FILTER_FUNCTIONS_JAVA + ");", toJava); | |
104 | } | |
105 | ||
106 | @Test | |
107 | public void testFilterReturn() { | |
108 | FilterReturn filterReturn = new FilterReturn(DUMMY_HANDLE); | |
109 | ||
110 | String toJava = filterReturn.toJava(null); | |
111 | ||
112 | Assert.assertEquals("handle = MethodHandles.filterReturnValue(handle, " + FilterReturn.FILTER_FUNCTION_JAVA + ");", toJava); | |
113 | } | |
114 | ||
115 | @Test | |
116 | public void testFold() { | |
117 | Fold fold = new Fold(DUMMY_HANDLE); | |
118 | ||
119 | String toJava = fold.toJava(null); | |
120 | ||
121 | Assert.assertEquals("handle = MethodHandles.foldArguments(handle, " + Fold.FOLD_FUNCTION_JAVA + ");", toJava); | |
122 | } | |
123 | ||
124 | @Test | |
125 | public void testInsert() { | |
126 | Insert insert = new Insert(0, new Class[] {int.class, double.class, Object.class}, 1L, 1.0F, "hello"); | |
127 | ||
128 | String toJava = insert.toJava(null); | |
129 | ||
130 | Assert.assertEquals("handle = MethodHandles.insertArguments(handle, 0, (int)1L, (double)1.0F, (java.lang.Object)value3);", toJava); | |
131 | } | |
132 | ||
133 | @Test | |
134 | public void testSpread() { | |
135 | Spread spread = new Spread(OBJECTARRAY_HANDLE.type(), Object.class, String.class, Integer.class); | |
136 | ||
137 | String toJava = spread.toJava(null); | |
138 | ||
139 | Assert.assertEquals("handle = handle.asSpreader(java.lang.Object[].class, 3);", toJava); | |
140 | } | |
141 | ||
142 | @Test | |
143 | public void testVarargs() { | |
144 | Varargs varargs = new Varargs(OBJECTS_HANDLE.type(), 0, Object[].class); | |
145 | ||
146 | String toJava = varargs.toJava(null); | |
147 | ||
148 | Assert.assertEquals("handle = handle.asVarargsCollector(java.lang.Object[].class).asType(" + Transform.generateMethodType(OBJECTS_HANDLE.type()) + ");", toJava); | |
149 | } | |
150 | ||
151 | public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); | |
152 | ||
153 | private static final MethodHandle DUMMY_HANDLE = Binder.from(void.class).invokeStaticQuiet(LOOKUP, ToJavaTest.class, "dummy"); | |
154 | private static void dummy() {} | |
155 | ||
156 | private static final MethodHandle OBJECTARRAY_HANDLE = Binder.from(void.class, Object[].class).invokeStaticQuiet(LOOKUP, ToJavaTest.class, "objectArray"); | |
157 | private static void objectArray(Object[] ary) {} | |
158 | ||
159 | private static final MethodHandle OBJECTS_HANDLE = Binder.from(void.class, Object.class, Object.class, Object.class).invokeStaticQuiet(LOOKUP, ToJavaTest.class, "objects"); | |
160 | private static void objects(Object o, Object p, Object q) {} | |
161 | } |