pax_global_header 0000666 0000000 0000000 00000000064 12645741720 0014522 g ustar 00root root 0000000 0000000 52 comment=8b05f6e38747d98084b1479ecd5bde4432a82644
invokebinder-invokebinder-1.7/ 0000775 0000000 0000000 00000000000 12645741720 0016525 5 ustar 00root root 0000000 0000000 invokebinder-invokebinder-1.7/.gitignore 0000664 0000000 0000000 00000000027 12645741720 0020514 0 ustar 00root root 0000000 0000000 /target/
/.idea/
*.iml
invokebinder-invokebinder-1.7/.travis.yml 0000664 0000000 0000000 00000000017 12645741720 0020634 0 ustar 00root root 0000000 0000000 language: java
invokebinder-invokebinder-1.7/LICENSE 0000664 0000000 0000000 00000026136 12645741720 0017542 0 ustar 00root root 0000000 0000000
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
invokebinder-invokebinder-1.7/README.markdown 0000664 0000000 0000000 00000002002 12645741720 0021220 0 ustar 00root root 0000000 0000000 Introduction
============
This library hopes to provide a more friendly DSL for binding method handles.
Unlike the normal MethodHandle API, handles are bound forward from a source
MethodType and eventually adapted to a final target MethodHandle. Along the way
the transformations are pushed onto a stack and eventually applied in reverse
order, as the standard API demands.
Examples
========
Transformation calls can be chained. They are not applied until an eventual
"invoke" is called with the target endpoint MethodHandle.
MethodHandle mh = Binder
.from(String.class, String.class, String.class) // String w(String, String)
.drop(1, String.class) // String x(String)
.insert(0, 'hello') // String y(String, String)
.cast(String.class, CharSequence.class, Object.class) // String z(CharSequence, Object)
.invoke(someTargetHandle);
Status
======
This is currently under development. Not all transformations from the MethodHandle
API are yet supported.
Contributors are welcome :) invokebinder-invokebinder-1.7/nb-configuration.xml 0000664 0000000 0000000 00000001776 12645741720 0022526 0 ustar 00root root 0000000 0000000
* MethodHandle mh = Binder * .from(String.class, String.class, String.class) // String w(String, String) * .drop(1, String.class) // String x(String) * .insert(0, 'hello') // String y(String, String) * .cast(String.class, CharSequence.class, Object.class) // String z(CharSequence, Object)String * .invoke(someTargetHandle); **/ public class Binder { private final Logger logger = Logger.getLogger("Invoke Binder"); private final List
* Signature sig = Signature.returning(String.class).appendArg("a", int.class).appendArg("b", int.class); * MethodHandle handle = handleThatTakesOneInt(); * MethodHandle newHandle = sig.permuteTo(handle, "b"); ** * @param target the method handle to target * @param permuteArgs the arguments to permute * @return a new handle that permutes appropriate positions based on the * given permute args */ public MethodHandle permuteWith(MethodHandle target, String... permuteArgs) { return MethodHandles.permuteArguments(target, methodType, to(permute(permuteArgs))); } /** * Produce a new SmartHandle by permuting this Signature's arguments to the * Signature of a target SmartHandle. The new SmartHandle's signature will * match this one, permuting those arguments and invoking the target handle. * * @param target the SmartHandle to use as a permutation target * @return a new SmartHandle that permutes this Signature's args into a call * to the target SmartHandle. * @see Signature#permuteWith(java.lang.invoke.MethodHandle, java.lang.String[]) */ public SmartHandle permuteWith(SmartHandle target) { String[] argNames = target.signature().argNames(); return new SmartHandle(this, permuteWith(target.handle(), argNames)); } /** * Generate an array of argument offsets based on permuting this signature * to the given signature. * * @param other the signature to target * @return an array of argument offsets that will permute to the given * signature */ public int[] to(Signature other) { return nonMatchingTo(other.argNames); } /** * Generate an array of argument offsets based on permuting this signature * to the given signature. Repeats are permitted, and the patterns will be * matched against actual argument names using regex matching. * * @param otherArgPatterns the argument name patterns to permute * @return an array of argument offsets that will permute to the matching * argument names */ public int[] to(String... otherArgPatterns) { return to(permute(otherArgPatterns)); } private int[] nonMatchingTo(String... otherArgNames) { int[] offsets = new int[otherArgNames.length]; int i = 0; for (String arg : otherArgNames) { int pos = -1; for (int offset = 0; offset < argNames.length; offset++) { if (argNames[offset].equals(arg)) { pos = offset; break; } } assert pos >= 0 : "argument not found: \"" + arg + "\""; offsets[i++] = pos; } return offsets; } } invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/SmartBinder.java 0000664 0000000 0000000 00000133754 12645741720 0031132 0 ustar 00root root 0000000 0000000 /* * Copyright 2013-2014 headius. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.headius.invokebinder; import java.io.PrintStream; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles.Lookup; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; /** * Maintains both a Binder, for building a series of transformations, and a * current Signature that maps symbolic names to arguments. Transformations * normally performed with Binder using argument indices can be done instead * using argument names and wildcards. * * TODO: Examples, or links to wiki examples. * * @author headius */ public class SmartBinder { private final Signature start; private final List
binder = binder.spread("str", 5)
*
* The resulting signature will have five trailing arguments named
* "arg0" through "arg4".
*
* @param baseName the base name from which to create the new argument names
* @param count the count of arguments to spread
* @return a new SmartBinder with the spread applied
*/
public SmartBinder spread(String baseName, int count) {
return new SmartBinder(this, signature().spread(baseName, count), binder.spread(count));
}
///////////////////////////////////////////////////////////////////////////
// INSERTS, based on MethodHandles.insertArguments.
///////////////////////////////////////////////////////////////////////////
/**
* Insert an argument into the argument list at the given index with the
* given name and value.
*
* @param index the index at which to insert the argument
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the insert applied
*/
public SmartBinder insert(int index, String name, Object value) {
return new SmartBinder(this, signature().insertArg(index, name, value.getClass()), binder.insert(index, value));
}
/**
* Insert an argument into the argument list at the given index with the
* given name and value.
*
* @param index the index at which to insert the argument
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the insert applied
*/
public SmartBinder insert(int index, String name, boolean value) {
return new SmartBinder(this, signature().insertArg(index, name, boolean.class), binder.insert(index, value));
}
/**
* Insert an argument into the argument list at the given index with the
* given name and value.
*
* @param index the index at which to insert the argument
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the insert applied
*/
public SmartBinder insert(int index, String name, byte value) {
return new SmartBinder(this, signature().insertArg(index, name, byte.class), binder.insert(index, value));
}
/**
* Insert an argument into the argument list at the given index with the
* given name and value.
*
* @param index the index at which to insert the argument
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the insert applied
*/
public SmartBinder insert(int index, String name, short value) {
return new SmartBinder(this, signature().insertArg(index, name, short.class), binder.insert(index, value));
}
/**
* Insert an argument into the argument list at the given index with the
* given name and value.
*
* @param index the index at which to insert the argument
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the insert applied
*/
public SmartBinder insert(int index, String name, char value) {
return new SmartBinder(this, signature().insertArg(index, name, char.class), binder.insert(index, value));
}
/**
* Insert an argument into the argument list at the given index with the
* given name and value.
*
* @param index the index at which to insert the argument
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the insert applied
*/
public SmartBinder insert(int index, String name, int value) {
return new SmartBinder(this, signature().insertArg(index, name, int.class), binder.insert(index, value));
}
/**
* Insert an argument into the argument list at the given index with the
* given name and value.
*
* @param index the index at which to insert the argument
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the insert applied
*/
public SmartBinder insert(int index, String name, long value) {
return new SmartBinder(this, signature().insertArg(index, name, long.class), binder.insert(index, value));
}
/**
* Insert an argument into the argument list at the given index with the
* given name and value.
*
* @param index the index at which to insert the argument
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the insert applied
*/
public SmartBinder insert(int index, String name, float value) {
return new SmartBinder(this, signature().insertArg(index, name, float.class), binder.insert(index, value));
}
/**
* Insert an argument into the argument list at the given index with the
* given name and value.
*
* @param index the index at which to insert the argument
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the insert applied
*/
public SmartBinder insert(int index, String name, double value) {
return new SmartBinder(this, signature().insertArg(index, name, double.class), binder.insert(index, value));
}
/**
* Insert an argument into the argument list at the given index with the
* given name and value.
*
* @param index the index at which to insert the argument
* @param name the name of the new argument
* @param type the type to use in the new signature
* @param value the value of the new argument
* @return a new SmartBinder with the insert applied
*/
public SmartBinder insert(int index, String name, Class> type, Object value) {
return new SmartBinder(this, signature().insertArg(index, name, type), binder.insert(index, type, value));
}
/**
* Insert arguments into the argument list at the given index with the
* given names and values.
*
* @param index the index at which to insert the arguments
* @param names the names of the new arguments
* @param types the types of the new arguments
* @param values the values of the new arguments
* @return a new SmartBinder with the insert applied
*/
public SmartBinder insert(int index, String[] names, Class>[] types, Object... values) {
return new SmartBinder(this, signature().insertArgs(index, names, types), binder.insert(index, types, values));
}
/**
* Append the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the append applied
*/
public SmartBinder append(String name, Object value) {
return new SmartBinder(this, signature().appendArg(name, value.getClass()), binder.append(value));
}
/**
* Append the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the append applied
*/
public SmartBinder append(String name, boolean value) {
return new SmartBinder(this, signature().appendArg(name, boolean.class), binder.append(value));
}
/**
* Append the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the append applied
*/
public SmartBinder append(String name, byte value) {
return new SmartBinder(this, signature().appendArg(name, byte.class), binder.append(value));
}
/**
* Append the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the append applied
*/
public SmartBinder append(String name, short value) {
return new SmartBinder(this, signature().appendArg(name, short.class), binder.append(value));
}
/**
* Append the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the append applied
*/
public SmartBinder append(String name, char value) {
return new SmartBinder(this, signature().appendArg(name, char.class), binder.append(value));
}
/**
* Append the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the append applied
*/
public SmartBinder append(String name, int value) {
return new SmartBinder(this, signature().appendArg(name, int.class), binder.append(value));
}
/**
* Append the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the append applied
*/
public SmartBinder append(String name, long value) {
return new SmartBinder(this, signature().appendArg(name, long.class), binder.append(value));
}
/**
* Append the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the append applied
*/
public SmartBinder append(String name, float value) {
return new SmartBinder(this, signature().appendArg(name, float.class), binder.append(value));
}
/**
* Append the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the append applied
*/
public SmartBinder append(String name, double value) {
return new SmartBinder(this, signature().appendArg(name, double.class), binder.append(value));
}
/**
* Append the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param type the type to use in the new signature
* @param value the value of the new argument
* @return a new SmartBinder with the append applied
*/
public SmartBinder append(String name, Class> type, Object value) {
return new SmartBinder(this, signature().appendArg(name, type), binder.append(new Class>[]{type}, value));
}
/**
* Append the given arguments to the argument list, assigning them the
* given names.
*
* @param names the names of the new arguments
* @param types the types to use in the new signature
* @param values the values of the new arguments
* @return a new SmartBinder with the append applied
*/
public SmartBinder append(String[] names, Class>[] types, Object... values) {
return new SmartBinder(this, signature().appendArgs(names, types), binder.append(types, values));
}
/**
* Prepend the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the prepend applied
*/
public SmartBinder prepend(String name, Object value) {
return new SmartBinder(this, signature().prependArg(name, value.getClass()), binder.prepend(value));
}
/**
* Prepend the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the prepend applied
*/
public SmartBinder prepend(String name, boolean value) {
return new SmartBinder(this, signature().prependArg(name, boolean.class), binder.prepend(value));
}
/**
* Prepend the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the prepend applied
*/
public SmartBinder prepend(String name, byte value) {
return new SmartBinder(this, signature().prependArg(name, byte.class), binder.prepend(value));
}
/**
* Prepend the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the prepend applied
*/
public SmartBinder prepend(String name, short value) {
return new SmartBinder(this, signature().prependArg(name, short.class), binder.prepend(value));
}
/**
* Prepend the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the prepend applied
*/
public SmartBinder prepend(String name, char value) {
return new SmartBinder(this, signature().prependArg(name, char.class), binder.prepend(value));
}
/**
* Prepend the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the prepend applied
*/
public SmartBinder prepend(String name, int value) {
return new SmartBinder(this, signature().prependArg(name, int.class), binder.prepend(value));
}
/**
* Prepend the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the prepend applied
*/
public SmartBinder prepend(String name, long value) {
return new SmartBinder(this, signature().prependArg(name, long.class), binder.prepend(value));
}
/**
* Prepend the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the prepend applied
*/
public SmartBinder prepend(String name, float value) {
return new SmartBinder(this, signature().prependArg(name, float.class), binder.prepend(value));
}
/**
* Prepend the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param value the value of the new argument
* @return a new SmartBinder with the prepend applied
*/
public SmartBinder prepend(String name, double value) {
return new SmartBinder(this, signature().prependArg(name, double.class), binder.prepend(value));
}
/**
* Prepend the given argument to the argument list, assigning it the
* given name.
*
* @param name the name of the new argument
* @param type the type to use in the new signature
* @param value the value of the new argument
* @return a new SmartBinder with the prepend applied
*/
public SmartBinder prepend(String name, Class> type, Object value) {
return new SmartBinder(this, signature().prependArg(name, type), binder.prepend(type, value));
}
/**
* Prepend the given arguments to the argument list, assigning them the
* given name.
*
* @param names the names of the new arguments
* @param types the types to use in the new signature
* @param values the values of the new arguments
* @return a new SmartBinder with the prepend applied
*/
public SmartBinder prepend(String[] names, Class>[] types, Object... values) {
return new SmartBinder(this, signature().prependArgs(names, types), binder.prepend(types, values));
}
///////////////////////////////////////////////////////////////////////////
// DROPS, based on MethodHandles.dropArguments.
///////////////////////////////////////////////////////////////////////////
/**
* Drop the argument with the given name.
*
* @param name the name of the argument to drop
* @return a new SmartBinder with the drop applied
*/
public SmartBinder drop(String name) {
int index = signature().argOffset(name);
return new SmartBinder(this, signature().dropArg(index), binder.drop(index));
}
/**
* Drop the last argument.
*
* @return a new SmartBinder with the drop applied
*/
public SmartBinder dropLast() {
return dropLast(1);
}
/**
* Drop the last N arguments.
*
* @param count the count of arguments to drop
* @return a new SmartBinder with the drop applied
*/
public SmartBinder dropLast(int count) {
return new SmartBinder(this, signature().dropLast(count), binder.dropLast(count));
}
/**
* Drop the first argument.
*
* @return a new SmartBinder with the drop applied
*/
public SmartBinder dropFirst() {
return dropFirst(1);
}
/**
* Drop the first N arguments.
*
* @param count the count of arguments to drop
* @return a new SmartBinder with the drop applied
*/
public SmartBinder dropFirst(int count) {
return new SmartBinder(this, signature().dropFirst(count), binder.dropFirst(count));
}
///////////////////////////////////////////////////////////////////////////
// COLLECTS, based on MethodHandle#asCollector
///////////////////////////////////////////////////////////////////////////
/**
* Collect arguments matching namePattern into an trailing array argument
* named outName.
*
* 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
* @return a new SmartBinder with the collect applied
*/
public SmartBinder collect(String outName, String namePattern) {
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()));
}
///////////////////////////////////////////////////////////////////////////
// CASTS, based on MethodHandles.explicitCastArguments and MethodHandle.asType.
///////////////////////////////////////////////////////////////////////////
/**
* Cast the incoming arguments to the types in the given signature. The
* argument count must match, but the names in the target signature are
* ignored.
*
* @param target the Signature to which arguments should be cast
* @return a new SmartBinder with the cast applied
*/
public SmartBinder cast(Signature target) {
return new SmartBinder(target, binder.cast(target.type()));
}
/**
* Cast the incoming arguments to the return and argument types given. The
* argument count must match.
*
* @param returnType the return type for the casted signature
* @param argTypes the types of the arguments for the casted signature
* @return a new SmartBinder with the cast applied
*/
public SmartBinder cast(Class> returnType, Class>... argTypes) {
return new SmartBinder(this, new Signature(returnType, argTypes, signature().argNames()), binder.cast(returnType, argTypes));
}
/**
* Cast the incoming arguments to the return, first argument type, and
* remaining argument types. Provide for convenience when dealing with
* virtual method argument lists, which frequently omit the target
* object.
*
* @param returnType the return type for the casted signature
* @param firstArg the type of the first argument for the casted signature
* @param restArgs the types of the remaining arguments for the casted signature
* @return a new SmartBinder with the cast applied.
*/
public SmartBinder castVirtual(Class> returnType, Class> firstArg, Class>... restArgs) {
return new SmartBinder(this, new Signature(returnType, firstArg, restArgs, signature().argNames()), binder.castVirtual(returnType, firstArg, restArgs));
}
/**
* Cast the named argument to the given type.
*
* @param name the name of the argument to cast
* @param type the type to which that argument will be cast
* @return a new SmartBinder with the cast applied
*/
public SmartBinder castArg(String name, Class> type) {
Signature newSig = signature().replaceArg(name, name, type);
return new SmartBinder(this, newSig, binder.cast(newSig.type()));
}
/**
* Cast the return value to the given type.
*
* Example: Our current signature is (String)String but the method this
* handle will eventually call returns CharSequence.
*
* binder = binder.castReturn(CharSequence.class);
*
* Our handle will now successfully find and call the target method and
* propagate the returned CharSequence as a String.
*
* @param type the new type for the return value
* @return a new SmartBinder
*/
public SmartBinder castReturn(Class> type) {
return new SmartBinder(this, signature().changeReturn(type), binder.cast(type, binder.type().parameterArray()));
}
///////////////////////////////////////////////////////////////////////////
// FILTERS, based on MethodHandles.filterReturnValue and filterArguments.
///////////////////////////////////////////////////////////////////////////
/**
* Use the given filter function to transform the return value at this
* point in the binder. The filter will be inserted into the handle, and
* return values will pass through it before continuing.
*
* The filter's argument must match the expected return value downstream
* from this point in the binder, and the return value must match the
* return value at this point in the binder.
*
* @param filter the function to use to transform the return value at this point
* @return a new SmartBinder with the filter applied
*/
public SmartBinder filterReturn(MethodHandle filter) {
return new SmartBinder(this, signature().changeReturn(filter.type().returnType()), binder.filterReturn(filter));
}
/**
* Use the given filter function to transform the return value at this
* point in the binder. The filter will be inserted into the handle, and
* return values will pass through it before continuing.
*
* The filter's argument must match the expected return value downstream
* from this point in the binder, and the return value must match the
* return value at this point in the binder.
*
* @param filter the function to use to transform the return value at this point
* @return a new SmartBinder with the filter applied
*/
public SmartBinder filterReturn(SmartHandle filter) {
return new SmartBinder(this, signature().changeReturn(filter.signature().type().returnType()), binder.filterReturn(filter.handle()));
}
///////////////////////////////////////////////////////////////////////////
// INVOKES, terminating the handle chain at a concrete target
///////////////////////////////////////////////////////////////////////////
/**
* Terminate this binder by looking up the named virtual method on the
* first argument's type. Perform the actual method lookup using the given
* Lookup object.
*
* @param lookup the Lookup to use for handle lookups
* @param name the name of the target virtual method
* @return a SmartHandle with this binder's starting signature, bound
* to the target method
* @throws NoSuchMethodException if the named method with current signature's types does not exist
* @throws IllegalAccessException if the named method is not accessible to the given Lookup
*/
public SmartHandle invokeVirtual(Lookup lookup, String name) throws NoSuchMethodException, IllegalAccessException {
return new SmartHandle(start, binder.invokeVirtual(lookup, name));
}
/**
* Terminate this binder by looking up the named virtual method on the
* first argument's type. Perform the actual method lookup using the given
* Lookup object. If the lookup fails, a RuntimeException will be raised,
* containing the actual reason. This method is for convenience in (for
* example) field declarations, where checked exceptions noise up code
* that can't recover anyway.
*
* Use this in situations where you would not expect your library to be
* usable if the target method can't be acquired.
*
* @param lookup the Lookup to use for handle lookups
* @param name the name of the target virtual method
* @return a SmartHandle with this binder's starting signature, bound
* to the target method
*/
public SmartHandle invokeVirtualQuiet(Lookup lookup, String name) {
return new SmartHandle(start, binder.invokeVirtualQuiet(lookup, name));
}
/**
* Terminate this binder by looking up the named static method on the
* given target type. Perform the actual method lookup using the given
* Lookup object.
*
* @param lookup the Lookup to use for handle lookups
* @param target the type on which to find the static method
* @param name the name of the target static method
* @return a SmartHandle with this binder's starting signature, bound
* to the target method
* @throws NoSuchMethodException if the named method with current signature's types does not exist
* @throws IllegalAccessException if the named method is not accessible to the given Lookup
*/
public SmartHandle invokeStatic(Lookup lookup, Class> target, String name) throws NoSuchMethodException, IllegalAccessException {
return new SmartHandle(start, binder.invokeStatic(lookup, target, name));
}
/**
* Terminate this binder by looking up the named static method on the
* given target type. Perform the actual method lookup using the given
* Lookup object. If the lookup fails, a RuntimeException will be raised,
* containing the actual reason. This method is for convenience in (for
* example) field declarations, where checked exceptions noise up code
* that can't recover anyway.
*
* Use this in situations where you would not expect your library to be
* usable if the target method can't be acquired.
*
* @param lookup the Lookup to use for handle lookups
* @param target the type on which to find the static method
* @param name the name of the target static method
* @return a SmartHandle with this binder's starting signature, bound
* to the target method
*/
public SmartHandle invokeStaticQuiet(Lookup lookup, Class> target, String name) {
return new SmartHandle(start, binder.invokeStaticQuiet(lookup, target, name));
}
/**
* Terminate this binder by invoking the given target handle. The signature
* of this binder is not compared to the signature of the given
* SmartHandle.
*
* @param target the handle to invoke
* @return a new SmartHandle with this binder's starting signature, bound
* through to the given handle
*/
public SmartHandle invoke(SmartHandle target) {
return new SmartHandle(start, binder.invoke(target.handle()));
}
/**
* Terminate this binder by invoking the given target handle.
*
* @param target the handle to invoke
* @return a new SmartHandle with this binder's starting signature, bound
* through to the given handle
*/
public SmartHandle invoke(MethodHandle target) {
return new SmartHandle(start, binder.invoke(target));
}
/**
* Terminate this binder by setting an array element based on the current
* signature. The signature should have the array as its first argument,
* an integer index as its second, and an appropriately-typed value as its
* third. It should have a void return value.
*
* Invoking the resulting handle will (eventually) perform the array
* assignment.
*
* @return a new SmartHandle with this binder's starting signature, bound
* to an array assignment operation
*/
public SmartHandle arrayGet() {
return new SmartHandle(start, binder.arrayGet());
}
/**
* Terminate this binder by getting an array element based on the current
* signature. The signature should have the array as its first argument and
* an integer index as its second, and an appropriately-typed return value.
*
* Invoking the resulting handle will (eventually) perform the array
* assignment.
*
* @return a new SmartHandle with this binder's starting signature, bound
* to an array dereference operation
*/
public SmartHandle arraySet() {
return new SmartHandle(start, binder.arraySet());
}
/**
* Terminate this binder by returning its sole remaining argument. The
* signature must take only one argument whose type matches the return
* type.
*
* Invoking the resulting handle will (eventually) return the argument
* passed in at this point.
*
* @return a new SmartHandle with this binder's starting signature that
* simply returns its sole received argument
*/
public SmartHandle identity() {
return new SmartHandle(start, binder.identity());
}
///////////////////////////////////////////////////////////////////////////
// OTHER UTILITIES
///////////////////////////////////////////////////////////////////////////
/**
* Print this binder's current signature to System.out.
*
* @return this SmartBinder
*/
public SmartBinder printSignature() {
return printSignature(System.out);
}
/**
* Print this binder's current signature to the give PrintStream.
*
* @return this SmartBinder
*/
public SmartBinder printSignature(PrintStream ps) {
ps.println(signature().toString());
return this;
}
/**
* Produce a SmartHandle from this binder that invokes a leading
* MethodHandle argument with the remaining arguments.
*
* @return a SmartHandle that invokes its leading MethodHandle argument
*/
public SmartHandle invoker() {
return new SmartHandle(start, binder.invoker());
}
/**
* Filter the arguments matching the given pattern using the given filter function.
*
* @param pattern the regular expression pattern to match arguments
* @param filter the MethodHandle to use to filter the arguments
* @return a new SmartBinder with the filter applied
*/
public SmartBinder filter(String pattern, MethodHandle filter) {
String[] argNames = signature().argNames();
Pattern pat = Pattern.compile(pattern);
Binder newBinder = binder();
Signature newSig = signature();
for (int i = 0; i < argNames.length; i++) {
if (pat.matcher(argNames[i]).matches()) {
newBinder = newBinder.filter(i, filter);
newSig = newSig.argType(i, filter.type().returnType());
}
}
return new SmartBinder(newSig, newBinder);
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/SmartHandle.java 0000664 0000000 0000000 00000032325 12645741720 0031112 0 ustar 00root root 0000000 0000000 /*
* Copyright 2013-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
/**
* A tuple of a Signature and a java.lang.invoke.MethodHandle, providing
* features of both plus a number of MethodHandles.* methods in a simpler form.
*
* SmartHandle is provided as a way to couple a given MethodHandle to a
* Signature, allowing future adaptation of the MethodHandle to proceed using
* Signature's various shortcuts and conveniences.
*
* Example:
*
*
* // A signature that only wants the "context" and "args" arguments
* public static final Signature ARG_COUNT_CHECK_FOLD = Signature
* .returning(void.class)
* .appendArg("args", Object[].class);
*
* // The actual target signature for arg count checking, with min and max ints
* public static final Signature ARG_COUNT_CHECK_SIGNATURE = Signature
* .returning(int.class)
* .appendArg("args", Object[].class)
* .appendArg("min", int.class)
* .appendArg("max", int.class);
*
* // A SmartHandle for the arity-checking method, using the fold and signature
* // from above and inserting 1, 3 for min, max
* SmartHandle arityCheck = SmartBinder
* .from(ARITY_CHECK_FOLD)
* .append("min", 1)
* .append("max", 3)
* .cast(ARITY_CHECK_SIGNATURE)
* .invokeStaticQuiet(LOOKUP, ArgCountChecker.class, "checkArgumentCount");
*
* // The variable-arity call contaings other arguments plus the Object[] args.
* // Here, we can just fold with our arityCheck SmartHandle, which drops args
* // we are not interested in, passes along the args array, and ignores the
* // return value.
* variableCall = SmartBinder
* .from(VARIABLE_ARITY_SIGNATURE)
* .foldVoid(arityCheck)
* .invoke(directCall);
*
*
* @author headius
*/
public class SmartHandle {
/**
* The signature associated with this smart handle
*/
private final Signature signature;
/**
* The MethodHandle associated with this smart handle
*/
private final MethodHandle handle;
SmartHandle(Signature signature, MethodHandle handle) {
this.signature = signature;
this.handle = handle;
}
/**
* Create a new SmartHandle from the given Signature and MethodHandle.
*
* @param signature the signature for the new smart handle
* @param handle the method handle for the new smart handle
* @return a new SmartHandle
*/
public static SmartHandle from(Signature signature, MethodHandle handle) {
return new SmartHandle(signature, handle);
}
/**
* Create a new SmartHandle by performing a lookup on the given target class
* for the given method name with the given signature.
*
* @param lookup the MethodHandles.Lookup object to use
* @param target the class where the method is located
* @param name the name of the method
* @param signature the signature of the method
* @return a new SmartHandle based on the signature and looked-up MethodHandle
*/
public static SmartHandle findStaticQuiet(Lookup lookup, Class> target, String name, Signature signature) {
try {
return new SmartHandle(signature, lookup.findStatic(target, name, signature.type()));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* Get the Signature of this SmartHandle.
*
* @return the Signature of this SmartHandle
*/
public Signature signature() {
return signature;
}
/**
* Get the MethodHandle of this SmartHandle.
*
* @return the MethodHandle of this SmartHandle
*/
public MethodHandle handle() {
return handle;
}
/**
* Apply an argument into the handle at the given index, returning a new
* SmartHandle. The new handle will use the given value for the argument at
* the given index, accepting one fewer argument as a result. In other words,
* fix that argument (partial application) into the given handle.
*
* @param index the index of the argument in the new SmartHandle's Signature
* @param arg the argument value
* @return a new SmartHandle that already has applied the given argument
*/
public SmartHandle apply(int index, Object arg) {
return new SmartHandle(signature.dropArg(index), MethodHandles.insertArguments(handle, index, arg));
}
/**
* Apply an argument into the handle at the given name, returning a new
* SmartHandle. The new handle will use the given value for the argument at
* the given index, accepting one fewer argument as a result. In other words,
* fix that argument (partial application) into the given handle.
*
* @param name the name of the argument in the new SmartHandle's Signature
* @param arg the argument value
* @return a new SmartHandle that already has applied the given argument
*/
public SmartHandle apply(String name, Object arg) {
return new SmartHandle(signature.dropArg(name), MethodHandles.insertArguments(handle, signature.argOffset(name), arg));
}
/**
* Apply an argument into the handle at the end, returning a new
* SmartHandle. The new handle will use the given value for the last
* argument, accepting one fewer argument as a result. In other words,
* fix that argument (partial application) into the given handle.
*
* @param arg the argument value
* @return a new SmartHandle that already has applied the given argument
*/
public SmartHandle applyLast(Object arg) {
return new SmartHandle(signature.dropLast(), MethodHandles.insertArguments(handle, signature.type().parameterCount(), arg));
}
/**
* Drop an argument name and type from the handle at the given index, returning a new
* SmartHandle.
*
* @param beforeName name before which the dropped argument goes
* @param newName name of the argument
* @param type type of the argument
* @return a new SmartHandle with the additional argument
*/
public SmartHandle drop(String beforeName, String newName, Class> type) {
return new SmartHandle(signature.insertArg(beforeName, newName, type), MethodHandles.dropArguments(handle, signature.argOffset(beforeName), type));
}
/**
* Drop an argument from the handle at the given index, returning a new
* SmartHandle.
*
* @param index index before which the dropped argument goes
* @param newName name of the argument
* @param type type of the argument
* @return a new SmartHandle with the additional argument
*/
public SmartHandle drop(int index, String newName, Class> type) {
return new SmartHandle(signature.insertArg(index, newName, type), MethodHandles.dropArguments(handle, index, type));
}
/**
* Drop an argument from the handle at the end, returning a new
* SmartHandle.
*
* @param newName name of the argument
* @param type type of the argument
* @return a new SmartHandle with the additional argument
*/
public SmartHandle dropLast(String newName, Class> type) {
return new SmartHandle(signature.appendArg(newName, type), MethodHandles.dropArguments(handle, signature.argOffset(newName), type));
}
/**
* Use this SmartHandle as a test to guard target and fallback handles.
*
* @param target the "true" path for this handle's test
* @param fallback the "false" path for this handle's test
* @return a MethodHandle that performs the test and branch
*/
public MethodHandle guard(MethodHandle target, MethodHandle fallback) {
return MethodHandles.guardWithTest(handle, target, fallback);
}
/**
* Use this SmartHandle as a test to guard target and fallback handles.
*
* @param target the "true" path for this handle's test
* @param fallback the "false" path for this handle's test
* @return a new SmartHandle that performs the test and branch
*/
public SmartHandle guard(SmartHandle target, SmartHandle fallback) {
return new SmartHandle(target.signature, MethodHandles.guardWithTest(handle, target.handle, fallback.handle));
}
/**
* Bind the first argument of this SmartHandle to the given object,
* returning a new adapted handle.
*
* @param obj the object to which to bind this handle's first argument
* @return a new SmartHandle with the first argument dropped in favor of obj
*/
public SmartHandle bindTo(Object obj) {
return new SmartHandle(signature.dropFirst(), handle.bindTo(obj));
}
/**
* Create a new SmartHandle that converts arguments from the given type to
* the current signature's type, using the same argument names. This conversion
* is equivalent to MethodHandle#asType.
*
* @param incoming the target MethodType from which arguments will be converted
* @return a new SmartHandle that accepts the given argument types
*/
public SmartHandle convert(MethodType incoming) {
return new SmartHandle(new Signature(incoming, signature.argNames()), handle.asType(incoming));
}
/**
* Create a new SmartHandle that converts arguments from the given return
* type and argument types to the current signature's type, using the same
* argument names. This conversion is equivalent to MethodHandle#asType.
*
* @param returnType the return type of the new handle
* @param argTypes the argument types of the new handle
* @return a new SmartHandle that accepts the given argument types
*/
public SmartHandle convert(Class> returnType, Class>... argTypes) {
return convert(MethodType.methodType(returnType, argTypes));
}
/**
* Create a new SmartHandle that converts arguments from the given signature to
* the current signature's type with the new argument names. This conversion
* is equivalent to MethodHandle#asType.
*
* @param incoming the target MethodType from which arguments will be converted
* @return a new SmartHandle that accepts the given argument types
*/
public SmartHandle convert(Signature incoming) {
return new SmartHandle(incoming, handle.asType(incoming.type()));
}
/**
* Create a new SmartHandle that casts arguments from the given type to
* the current signature's type, using the same argument names. This casting
* is equivalent to MethodHandles#explicitCastArguments.
*
* @param incoming the target MethodType from which arguments will be converted
* @return a new SmartHandle that accepts the given argument types
*/
public SmartHandle cast(MethodType incoming) {
return new SmartHandle(new Signature(incoming, signature.argNames()), MethodHandles.explicitCastArguments(handle, incoming));
}
/**
* Create a new SmartHandle that casts arguments from the given signature to
* the current signature's type with the new argument names. This casting
* is equivalent to MethodHandle#asType.
*
* @param incoming the target MethodType from which arguments will be converted
* @return a new SmartHandle that accepts the given argument types
*/
public SmartHandle cast(Signature incoming) {
return new SmartHandle(incoming, MethodHandles.explicitCastArguments(handle, incoming.type()));
}
/**
* Create a new SmartHandle that casts arguments from the given return
* type and argument types to the current signature's type, using the same
* argument names. This casting is equivalent to MethodHandle#asType.
*
* @param returnType the return type of the new handle
* @param argTypes the argument types of the new handle
* @return a new SmartHandle that accepts the given argument types
*/
public SmartHandle cast(Class> returnType, Class>... argTypes) {
return cast(MethodType.methodType(returnType, argTypes));
}
/**
* Replace the return value with the given value, performing no other
* processing of the original value.
*
* @param type the type for the new return value
* @param value the new value to return
* @return a new SmartHandle that returns the given value
*/
public SmartHandle returnValue(Class> type, Object value) {
return new SmartHandle(signature.changeReturn(type), MethodHandles.filterReturnValue(handle, MethodHandles.constant(type, value)));
}
/**
* A human-readable String representation of this SamrtHandle.
*
* @return a String representation of this handle
*/
@Override
public String toString() {
return signature.toString() + "=>" + handle;
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/ 0000775 0000000 0000000 00000000000 12645741720 0030053 5 ustar 00root root 0000000 0000000 invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/Cast.java 0000664 0000000 0000000 00000003513 12645741720 0031612 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
/**
* A casting transform.
*
* Equivalent call: MethodHandles.explicitCastArguments(MethodHandle, MethodType).
*/
public class Cast extends Transform {
private final MethodType type;
public Cast(MethodType type) {
this.type = type;
}
public MethodHandle up(MethodHandle target) {
// If target's return type is void, it is replaced with (Object)null.
// If incoming signature expects something else, additional cast is required.
// TODO: Is this a bug in JDK?
if (target.type().returnType() == void.class) {
target = MethodHandles.explicitCastArguments(target, type);
return MethodHandles.explicitCastArguments(target, type);
} else {
return MethodHandles.explicitCastArguments(target, type);
}
}
public MethodType down(MethodType type) {
for (int i = 0; i < type.parameterCount(); i++) {
type = type.changeParameterType(i, type.parameterArray()[i]);
}
return type;
}
public String toString() {
return "cast args to " + type;
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/Catch.java 0000664 0000000 0000000 00000002737 12645741720 0031751 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
/**
* An exception-handling transform.
*
* Equivalent call: MethodHandles.catchException(MethodHandle, Class, MethodHandle).
*/
public class Catch extends Transform {
private final Class extends Throwable> throwable;
private final MethodHandle function;
public Catch(Class extends Throwable> throwable, MethodHandle function) {
this.throwable = throwable;
this.function = function;
}
public MethodHandle up(MethodHandle target) {
return MethodHandles.catchException(target, throwable, function);
}
public MethodType down(MethodType type) {
return type;
}
public String toString() {
return "catch exception type " + throwable + " using " + function;
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/Collect.java 0000664 0000000 0000000 00000006602 12645741720 0032307 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import com.headius.invokebinder.Binder;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
/**
* An argument-boxing transform with a fixed incoming size.
*
* Equivalent call: MethodHandle.asCollector(Class, int)
*/
public class Collect extends Transform {
private final MethodType source;
private final int index;
private final int count;
private final Class> arrayType;
public Collect(MethodType source, int index, Class> arrayType) {
this.source = source;
this.index = index;
this.count = source.parameterCount() - index;
this.arrayType = arrayType;
}
public Collect(MethodType source, int index, int count, Class> arrayType) {
this.source = source;
this.index = index;
this.count = count;
this.arrayType = arrayType;
}
public MethodHandle up(MethodHandle target) {
if (index + count == source.parameterCount()) {
// 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;
}
// 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 Binder.from(source)
.permute(movePermute)
.collect(source.parameterCount() - count, arrayType)
.permute(moveBackPermute)
.invoke(target);
}
}
public MethodType down(MethodType type) {
assertTypesAreCompatible();
return type
.dropParameterTypes(index, index + count)
.insertParameterTypes(index, arrayType);
}
private void assertTypesAreCompatible() {
Class> componentType = arrayType.getComponentType();
for (int i = index; i < index + count; i++) {
Class> in = source.parameterType(i);
assert in.isAssignableFrom(componentType)
: "incoming type " + in.getName() + " not compatible with " + componentType.getName() + "[]";
}
}
public String toString() {
return "collect at " + index + " into " + arrayType.getName();
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/Convert.java 0000664 0000000 0000000 00000003371 12645741720 0032342 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
/**
* An argument conversion transform.
*
* Equivalent call: MethodHandles.asType(MethodHandle, MethodType).
*/
public class Convert extends Transform {
private final MethodType type;
public Convert(MethodType type) {
this.type = type;
}
public MethodHandle up(MethodHandle target) {
// If target's return type is void, it is replaced with (Object)null.
// If incoming signature expects something else, additional cast is required.
// TODO: Is this a bug in JDK?
if (target.type().returnType() == void.class) {
return MethodHandles.explicitCastArguments(target.asType(type), type);
} else {
return target.asType(type);
}
}
public MethodType down(MethodType type) {
for (int i = 0; i < type.parameterCount(); i++) {
type = type.changeParameterType(i, type.parameterArray()[i]);
}
return type;
}
public String toString() {
return "convert args to " + type;
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/Drop.java 0000664 0000000 0000000 00000002726 12645741720 0031631 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
/**
* An argument drop transform.
*
* Equivalent call: MethodHandles.dropArguments(MethodHandle, int, MethodType).
*/
public class Drop extends Transform {
private final int position;
private final Class>[] types;
public Drop(int position, Class>... types) {
this.position = position;
this.types = types;
}
public MethodHandle up(MethodHandle target) {
return MethodHandles.dropArguments(target, position, types);
}
public MethodType down(MethodType type) {
return type.dropParameterTypes(position, position + types.length);
}
public String toString() {
return "drop " + Arrays.toString(types) + " at " + position;
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/Filter.java 0000664 0000000 0000000 00000003145 12645741720 0032146 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
/**
* An argument-filtering transform.
*
* Equivalent call: MethodHandles.filterArguments(MethodHandle, int, MethodHandle...).
*/
public class Filter extends Transform {
private final int index;
private final MethodHandle[] functions;
public Filter(int index, MethodHandle... functions) {
this.index = index;
this.functions = functions;
}
public MethodHandle up(MethodHandle target) {
return MethodHandles.filterArguments(target, index, functions);
}
public MethodType down(MethodType type) {
for (int i = 0; i < functions.length; i++) {
type = type.changeParameterType(index + i, functions[i].type().returnType());
}
return type;
}
public String toString() {
return "fold args from " + index + " with " + Arrays.toString(functions);
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/FilterReturn.java 0000664 0000000 0000000 00000003401 12645741720 0033341 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import com.headius.invokebinder.InvalidTransformException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
/**
* An return-filtering transform.
*
* Equivalent call: MethodHandles.filterReturn(MethodHandle, MethodHandle).
*/
public class FilterReturn extends Transform {
private final MethodHandle function;
public FilterReturn(MethodHandle function) {
this.function = function;
}
public MethodHandle up(MethodHandle target) {
return MethodHandles.filterReturnValue(target, function);
}
public MethodType down(MethodType type) {
int count = function.type().parameterCount();
switch (count) {
case 0:
return type.changeReturnType(void.class);
case 1:
return type.changeReturnType(function.type().parameterType(0));
default:
throw new InvalidTransformException("return filter " + function + " does not accept zero or one argument");
}
}
public String toString() {
return "filter return with " + function;
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/Fold.java 0000664 0000000 0000000 00000002642 12645741720 0031606 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
/**
* An argument-folding transform.
*
* Equivalent call: MethodHandles.foldArguments(MethodHandle, MethodHandle).
*/
public class Fold extends Transform {
private final MethodHandle function;
public Fold(MethodHandle function) {
this.function = function;
}
public MethodHandle up(MethodHandle target) {
return MethodHandles.foldArguments(target, function);
}
public MethodType down(MethodType type) {
if (function.type().returnType() == void.class) return type;
return type.insertParameterTypes(0, function.type().returnType());
}
public String toString() {
return "fold args with " + function;
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/Insert.java 0000664 0000000 0000000 00000006713 12645741720 0032171 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
/**
* An argument insertion transform.
*
* Equivalent call: MethodHandles.insertArguments(MethodHandle, int, Object...).
*/
public class Insert extends Transform {
private final int position;
private final Class>[] types;
private final Object[] values;
public Insert(int position, Object... values) {
this.position = position;
this.values = values;
Class>[] types = new Class>[values.length];
for (int i = 0; i < values.length; i++) {
types[i] = values[i].getClass();
}
this.types = types;
}
public Insert(int position, boolean value) {
this.position = position;
this.values = new Object[]{value};
this.types = new Class[]{boolean.class};
}
public Insert(int position, byte value) {
this.position = position;
this.values = new Object[]{value};
this.types = new Class[]{byte.class};
}
public Insert(int position, short value) {
this.position = position;
this.values = new Object[]{value};
this.types = new Class[]{short.class};
}
public Insert(int position, char value) {
this.position = position;
this.values = new Object[]{value};
this.types = new Class[]{char.class};
}
public Insert(int position, int value) {
this.position = position;
this.values = new Object[]{value};
this.types = new Class[]{int.class};
}
public Insert(int position, long value) {
this.position = position;
this.values = new Object[]{value};
this.types = new Class[]{long.class};
}
public Insert(int position, float value) {
this.position = position;
this.values = new Object[]{value};
this.types = new Class[]{float.class};
}
public Insert(int position, double value) {
this.position = position;
this.values = new Object[]{value};
this.types = new Class[]{double.class};
}
public Insert(int position, Class>[] types, Object... values) {
this.position = position;
this.values = values;
this.types = types;
}
public MethodHandle up(MethodHandle target) {
return MethodHandles.insertArguments(target, position, values);
}
public MethodType down(MethodType type) {
return type.insertParameterTypes(position, types);
}
public String toString() {
return "insert " + Arrays.toString(types()) + " at " + position;
}
private Class>[] types() {
Class>[] types = new Class>[values.length];
for (int i = 0; i < types.length; i++) {
types[i] = values[i].getClass();
}
return types;
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/Permute.java 0000664 0000000 0000000 00000003731 12645741720 0032343 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import com.headius.invokebinder.InvalidTransformException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
/**
* A permutation transform.
*
* Equivalent call: MethodHandles.permuteArguments(MethodHandle, MethodType, int...)
*/
public class Permute extends Transform {
private final MethodType source;
private final int[] reorder;
public Permute(MethodType source, int... reorder) {
this.source = source;
this.reorder = reorder;
}
public MethodHandle up(MethodHandle target) {
return MethodHandles.permuteArguments(target, source, reorder);
}
public MethodType down(MethodType type) {
Class>[] types = new Class>[reorder.length];
for (int i = 0; i < reorder.length; i++) {
int typeIndex = reorder[i];
if (typeIndex < 0 || typeIndex >= type.parameterCount()) {
throw new InvalidTransformException("one or more permute indices (" + Arrays.toString(reorder) + ") out of bounds for " + source);
}
types[i] = type.parameterType(reorder[i]);
}
return MethodType.methodType(type.returnType(), types);
}
public String toString() {
return "permute " + source + " with " + Arrays.toString(reorder);
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/Spread.java 0000664 0000000 0000000 00000003410 12645741720 0032132 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import com.headius.invokebinder.InvalidTransformException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
/**
* An array-spreading transform.
*
* Equivalent call: MethodHandles.spreadInvoker(MethodType, int).bindTo(MethodHandle)
*/
public class Spread extends Transform {
private final MethodType source;
private final Class>[] spreadTypes;
public Spread(MethodType source, Class>... spreadTypes) {
this.source = source;
this.spreadTypes = spreadTypes;
}
public MethodHandle up(MethodHandle target) {
return target.asSpreader(source.parameterType(source.parameterCount() - 1), spreadTypes.length);
}
public MethodType down(MethodType type) {
int last = source.parameterCount() - 1;
if (!source.parameterArray()[last].isArray()) {
throw new InvalidTransformException("trailing argument is not []: " + source);
}
type = type.dropParameterTypes(last, last + 1);
return type.appendParameterTypes(spreadTypes);
}
public String toString() {
return "spread " + source + " to " + down(source);
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/Transform.java 0000664 0000000 0000000 00000002712 12645741720 0032673 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
/**
* Abstract reprensentation of some handle transform.
*/
public abstract class Transform {
/**
* Apply this transform upward from the given MethodHandle, producing
* a new handle.
*
* @param target the target handle
* @return the adapted handle
*/
public abstract MethodHandle up(MethodHandle target);
/**
* Apply this transform downward from an incoming MethodType, producing
* a new type.
*
* @param source the source type
* @return the new type
*/
public abstract MethodType down(MethodType source);
/**
* Return a string representation of this transform.
*
* @return a string representation of this transform
*/
public abstract String toString();
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/TryFinally.java 0000664 0000000 0000000 00000005470 12645741720 0033021 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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 try-finally transform.
*
* Equivalent call: A combination of folds and catches.
*
* MethodHandle exceptionHandler = [drop exception and invoke post logic]
* target = MethodHandles.catchException(target, Throwable.class, exceptionHandler)
* target = MethodHandles.foldArguments(post, target)
*/
public class TryFinally extends Transform {
private final MethodHandle post;
public TryFinally(MethodHandle post) {
this.post = post;
}
public MethodHandle up(MethodHandle target) {
MethodHandle exceptionHandler = Binder
.from(target.type().insertParameterTypes(0, Throwable.class).changeReturnType(void.class))
.drop(0)
.invoke(post);
MethodHandle rethrow = Binder
.from(target.type().insertParameterTypes(0, Throwable.class))
.fold(exceptionHandler)
.drop(1, target.type().parameterCount())
.throwException();
target = MethodHandles.catchException(target, Throwable.class, rethrow);
// if target returns a value, we must return it regardless of post
MethodHandle realPost = post;
if (target.type().returnType() != void.class) {
// modify post to ignore return value
MethodHandle newPost = Binder
.from(target.type().insertParameterTypes(0, target.type().returnType()).changeReturnType(void.class))
.drop(0)
.invoke(post);
// fold post into an identity chain that only returns the value
realPost = Binder
.from(target.type().insertParameterTypes(0, target.type().returnType()))
.fold(newPost)
.drop(1, target.type().parameterCount())
.identity();
}
return MethodHandles.foldArguments(realPost, target);
}
public MethodType down(MethodType type) {
return type;
}
public String toString() {
return "try/finally with " + post;
}
}
invokebinder-invokebinder-1.7/src/main/java/com/headius/invokebinder/transform/Varargs.java 0000664 0000000 0000000 00000003726 12645741720 0032333 0 ustar 00root root 0000000 0000000 /*
* Copyright 2012-2014 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder.transform;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
/**
* An argument-boxing transform.
*
* Equivalent call: MethodHandle.asVarargsCollector(Class)
*/
public class Varargs extends Transform {
private final MethodType source;
private int index;
private final Class> arrayType;
public Varargs(MethodType source, int index, Class> arrayType) {
this.source = source;
this.index = index;
this.arrayType = arrayType;
}
public MethodHandle up(MethodHandle target) {
return target.asVarargsCollector(arrayType).asType(source);
}
public MethodType down(MethodType type) {
assertTypesAreCompatible();
return type
.dropParameterTypes(index, source.parameterCount())
.appendParameterTypes(arrayType);
}
private void assertTypesAreCompatible() {
Class> componentType = arrayType.getComponentType();
for (int i = index; i < source.parameterCount(); i++) {
Class> in = source.parameterType(i);
assert componentType.isAssignableFrom(in)
: "incoming type " + in.getName() + " not compatible with " + componentType.getName() + "[]";
}
}
public String toString() {
return "varargs at " + index + " into " + arrayType.getName();
}
}
invokebinder-invokebinder-1.7/src/test/ 0000775 0000000 0000000 00000000000 12645741720 0020273 5 ustar 00root root 0000000 0000000 invokebinder-invokebinder-1.7/src/test/java/ 0000775 0000000 0000000 00000000000 12645741720 0021214 5 ustar 00root root 0000000 0000000 invokebinder-invokebinder-1.7/src/test/java/com/ 0000775 0000000 0000000 00000000000 12645741720 0021772 5 ustar 00root root 0000000 0000000 invokebinder-invokebinder-1.7/src/test/java/com/headius/ 0000775 0000000 0000000 00000000000 12645741720 0023414 5 ustar 00root root 0000000 0000000 invokebinder-invokebinder-1.7/src/test/java/com/headius/invokebinder/ 0000775 0000000 0000000 00000000000 12645741720 0026073 5 ustar 00root root 0000000 0000000 invokebinder-invokebinder-1.7/src/test/java/com/headius/invokebinder/BinderTest.java 0000664 0000000 0000000 00000110720 12645741720 0031002 0 ustar 00root root 0000000 0000000 package com.headius.invokebinder;
import org.junit.Test;
import static org.junit.Assert.*;
import java.io.ByteArrayOutputStream;
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.reflect.Method;
/**
* @author headius
*/
public class BinderTest {
private static final Lookup LOOKUP = MethodHandles.lookup();
@Test
public void testFrom() throws Throwable {
MethodHandle target = Subjects.concatHandle();
Binder binder1 = Binder
.from(String.class, String.class, Object.class)
.drop(1);
MethodHandle handle = Binder
.from(binder1)
.insert(1, "world")
.invoke(target);
assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object()));
}
@Test
public void testInsertPrimitive() throws Throwable {
Binder b1 = Binder
.from(void.class)
.insert(0, true);
assertEquals(MethodType.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());
Binder b3 = Binder
.from(void.class)
.insert(0, (short)1);
assertEquals(MethodType.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());
Binder b5 = Binder
.from(void.class)
.insert(0, 1);
assertEquals(MethodType.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());
Binder b7 = Binder
.from(void.class)
.insert(0, 1.0F);
assertEquals(MethodType.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());
MethodHandle target = intLongHandle();
MethodHandle handle = Binder
.from(String.class)
.insert(0, new Class[]{int.class, long.class}, 1, 1L)
.invoke(target);
assertEquals(MethodType.methodType(String.class), handle.type());
assertEquals("intLong ok", (String) handle.invokeExact());
}
@Test
public void testTo() throws Throwable {
Binder otherBinder = Binder
.from(String.class, String.class, int.class)
.drop(1)
.insert(1, ", world");
Binder thisBinder = Binder
.from(String.class)
.insert(0, "Hello")
.insert(1, 1);
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());
MethodHandle target = newBinder.invoke(Subjects.concatHandle());
assertEquals("Hello, world", (String)target.invokeExact());
}
@Test
public void testType() throws Throwable {
Binder binder = Binder
.from(String.class, String.class, Integer.class);
assertEquals(MethodType.methodType(String.class, String.class, Integer.class), binder.type());
binder = binder
.drop(1);
assertEquals(MethodType.methodType(String.class, String.class), binder.type());
}
@Test
public void testPrintType() throws Throwable {
Binder binder = Binder
.from(String.class, String.class, Integer.class);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
binder.printType(ps);
assertEquals("(String,Integer)String\n", baos.toString());
binder = binder
.drop(1);
baos = new ByteArrayOutputStream();
ps = new PrintStream(baos);
binder.printType(ps);
assertEquals("(String)String\n", baos.toString());
}
@Test
public void testInsert() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(String.class, String.class)
.insert(1, "world")
.invoke(target);
assertEquals(MethodType.methodType(String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, "));
MethodHandle target2 = Subjects.concatCharSequenceHandle();
MethodHandle handle2 = Binder
.from(String.class, String.class)
.insert(1, CharSequence.class, "world")
.invoke(target2);
assertEquals(MethodType.methodType(String.class, String.class), handle2.type());
assertEquals("Hello, world", (String) handle2.invokeExact("Hello, "));
}
@Test
public void testAppend() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(String.class, String.class, Object.class)
.append("world")
.drop(1)
.invoke(target);
assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object()));
MethodHandle target2 = Subjects.concatCharSequenceHandle();
MethodHandle handle2 = Binder
.from(String.class, String.class, Object.class)
.append(CharSequence.class, "world")
.drop(1)
.invoke(target2);
assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle2.type());
assertEquals("Hello, world", (String) handle2.invokeExact("Hello, ", new Object()));
}
@Test
public void testPrepend() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(String.class, Object.class, String.class)
.prepend("Hello, ")
.drop(1)
.invoke(target);
assertEquals(MethodType.methodType(String.class, Object.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact(new Object(), "world"));
MethodHandle target2 = Subjects.concatHandle();
MethodHandle handle2 = Binder
.from(String.class, Object.class, String.class)
.prepend(String.class, "Hello, ")
.drop(1)
.invoke(target2);
assertEquals(MethodType.methodType(String.class, Object.class, String.class), handle2.type());
assertEquals("Hello, world", (String) handle2.invokeExact(new Object(), "world"));
}
@Test
public void testDropInsert() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(String.class, String.class, Object.class)
.drop(1)
.insert(1, "world")
.invoke(target);
assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object()));
}
@Test
public void testDropLast() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(String.class, String.class, Object.class)
.dropLast()
.insert(1, "world")
.invoke(target);
assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object()));
handle = Binder
.from(String.class, String.class, Object.class, double.class)
.dropLast(2)
.insert(1, "world")
.invoke(target);
assertEquals(MethodType.methodType(String.class, String.class, Object.class, double.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object(), 1.0));
}
@Test
public void testDropFirst() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(String.class, Object.class, String.class)
.dropFirst()
.insert(1, "world")
.invoke(target);
assertEquals(MethodType.methodType(String.class, Object.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact(new Object(), "Hello, "));
handle = Binder
.from(String.class, Object.class, double.class, String.class)
.dropFirst(2)
.insert(1, "world")
.invoke(target);
assertEquals(MethodType.methodType(String.class, Object.class, double.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact(new Object(), 1.0, "Hello, "));
}
@Test
public void testDropAll() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(String.class, String.class, Object.class)
.dropAll()
.insert(0, "Hello, ", "world")
.invoke(target);
assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", new Object()));
}
@Test
public void testConvert() throws Throwable {
MethodHandle target = mixedHandle();
MethodHandle handle = Binder
.from(String.class, Object.class, Integer.class, Float.class)
.convert(target.type())
.invoke(target);
assertEquals(MethodType.methodType(String.class, Object.class, Integer.class, Float.class), handle.type());
assertEquals(null, (String) handle.invokeExact((Object) "foo", (Integer) 5, (Float) 5.0f));
}
@Test
public void testConvert2() throws Throwable {
MethodHandle target = mixedHandle();
MethodHandle handle = Binder
.from(String.class, Object.class, Integer.class, Float.class)
.convert(target.type().returnType(), target.type().parameterArray())
.invoke(target);
assertEquals(MethodType.methodType(String.class, Object.class, Integer.class, Float.class), handle.type());
assertEquals(null, (String)handle.invokeExact((Object)"foo", (Integer)5, (Float)5.0f));
}
@Test
public void testCast() throws Throwable {
MethodHandle target = mixedHandle();
MethodHandle handle = Binder
.from(String.class, Object.class, byte.class, int.class)
.cast(target.type())
.invoke(target);
assertEquals(MethodType.methodType(String.class, Object.class, byte.class, int.class), handle.type());
assertEquals(null, (String)handle.invokeExact((Object)"foo", (byte)5, 5));
}
@Test
public void testCast2() throws Throwable {
MethodHandle target = mixedHandle();
MethodHandle handle = Binder
.from(String.class, Object.class, byte.class, int.class)
.cast(target.type().returnType(), target.type().parameterArray())
.invoke(target);
assertEquals(MethodType.methodType(String.class, Object.class, byte.class, int.class), handle.type());
assertEquals(null, (String)handle.invokeExact((Object)"foo", (byte)5, 5));
}
@Test
public void testDropReorder() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(String.class, Integer.class, Float.class, String.class)
.drop(0, 2)
.permute(0, 0)
.invoke(target);
assertEquals(MethodType.methodType(String.class, Integer.class, Float.class, String.class), handle.type());
assertEquals("foofoo", (String)handle.invokeExact((Integer) 0, (Float) 0.0f, "foo"));
}
@Test
public void testSpread() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(String.class, Object[].class)
.spread(String.class, String.class)
.invoke(target);
assertEquals(MethodType.methodType(String.class, Object[].class), handle.type());
assertEquals("foobar", (String)handle.invokeExact(new Object[] {"foo", "bar"}));
}
@Test
public void testSpreadCount() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(String.class, String[].class)
.spread(2)
.invoke(target);
assertEquals(MethodType.methodType(String.class, String[].class), handle.type());
assertEquals("foobar", (String)handle.invokeExact(new String[] {"foo", "bar"}));
}
@Test
public void testCollect() throws Throwable {
MethodHandle handle = Binder
.from(String[].class, String.class, String.class, String.class)
.collect(1, String[].class)
.invokeStatic(LOOKUP, BinderTest.class, "varargs");
assertEquals(MethodType.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]);
MethodHandle handle2 = Binder
.from(Subjects.StringIntegerIntegerIntegerString.type())
.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("[foo, [1, 2, 3], bar]", (String)handle2.invokeExact("foo", new Integer(1), new Integer(2), new Integer(3), "bar"));
}
@Test
public void testVarargs() throws Throwable {
MethodHandle handle = Binder
.from(String[].class, String.class, String.class, String.class)
.varargs(1, String[].class)
.invokeStatic(LOOKUP, BinderTest.class, "varargs");
assertEquals(MethodType.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))
.varargs(0, Object[].class)
.invokeStatic(MethodHandles.publicLookup(), getClass(), "varargs");
assertEquals(foo.invokeWithArguments("value"), "value");
}
@Test
public void testConstant() throws Throwable {
MethodHandle handle = Binder
.from(String.class)
.constant("hello");
assertEquals(MethodType.methodType(String.class), handle.type());
assertEquals("hello", (String)handle.invokeExact());
}
@Test
public void testConstant2() throws Throwable {
MethodHandle handle = Binder
.from(Object.class)
.constant("hello");
assertEquals(MethodType.methodType(Object.class), handle.type());
assertEquals("hello", (Object)handle.invokeExact());
}
@Test
public void testIdentity() throws Throwable {
MethodHandle handle = Binder
.from(String.class, String.class)
.identity();
assertEquals(MethodType.methodType(String.class, String.class), handle.type());
assertEquals("hello", (String)handle.invokeExact("hello"));
}
@Test
public void testFold() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle fold = Binder
.from(String.class, String.class)
.drop(0)
.constant("yahoo");
MethodHandle handle = Binder
.from(String.class, String.class)
.fold(fold)
.invoke(target);
assertEquals(MethodType.methodType(String.class, String.class), handle.type());
assertEquals("yahoofoo", (String)handle.invokeExact("foo"));
}
@Test
public void testFoldStatic() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(LOOKUP, String.class, String.class)
.foldStatic(BinderTest.class, "alwaysYahooStatic")
.invoke(target);
assertEquals(MethodType.methodType(String.class, String.class), handle.type());
assertEquals("yahoofoo", (String)handle.invokeExact("foo"));
}
@Test
public void testFoldVirtual() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(LOOKUP, String.class, String.class)
.insert(0, this)
.foldVirtual("alwaysYahooVirtual")
.drop(1)
.invoke(target);
assertEquals(MethodType.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 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("foobazbarbaz", (String)handle.invokeExact("foo", "bar"));
}
@Test
public void testInvoke() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle handle = Binder
.from(String.class, String.class, String.class)
.invoke(target);
assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world"));
}
@Test
public void testInvokeReflected() throws Throwable {
Method target = Subjects.class.getMethod("concatStatic", String.class, String.class);
MethodHandle handle = Binder
.from(String.class, String.class, String.class)
.invoke(LOOKUP, target);
assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world"));
}
@Test
public void testInvokeReflected2() throws Throwable {
Method target = Subjects.class.getMethod("concatStatic", String.class, String.class);
MethodHandle handle = Binder
.from(String.class, String.class, String.class)
.invokeQuiet(LOOKUP, target);
assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world"));
}
@Test
public void testInvokeStatic() throws Throwable {
MethodHandle handle = Binder
.from(String.class, String.class, String.class)
.invokeStatic(LOOKUP, Subjects.class, "concatStatic");
assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world"));
}
@Test
public void testInvokeStatic2() throws Throwable {
MethodHandle handle = Binder
.from(String.class, String.class, String.class)
.invokeStaticQuiet(LOOKUP, Subjects.class, "concatStatic");
assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type());
assertEquals("Hello, world", (String) handle.invokeExact("Hello, ", "world"));
}
@Test
public void testInvokeVirtual() throws Throwable {
MethodHandle handle = Binder
.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("Hello, world", (String) handle.invokeExact(this, "Hello, ", "world"));
}
@Test
public void testInvokeVirtual2() throws Throwable {
MethodHandle handle = Binder
.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("Hello, world", (String) handle.invokeExact(this, "Hello, ", "world"));
}
@Test
public void testInvokeConstructor() throws Throwable {
MethodHandle handle = Binder
.from(Constructable.class, String.class, String.class)
.invokeConstructor(LOOKUP, Constructable.class);
assertEquals(MethodType.methodType(Constructable.class, String.class, String.class), handle.type());
assertEquals(new Constructable("foo", "bar"), (Constructable) handle.invokeExact("foo", "bar"));
}
@Test
public void testInvokeConstructor2() throws Throwable {
MethodHandle handle = Binder
.from(Constructable.class, String.class, String.class)
.invokeConstructorQuiet(LOOKUP, Constructable.class);
assertEquals(MethodType.methodType(Constructable.class, String.class, String.class), handle.type());
assertEquals(new Constructable("foo", "bar"), (Constructable) handle.invokeExact("foo", "bar"));
}
@Test
public void testGetField() throws Throwable {
Fields fields = new Fields();
MethodHandle handle = Binder
.from(String.class, Fields.class)
.getField(LOOKUP, "instanceField");
assertEquals(MethodType.methodType(String.class, Fields.class), handle.type());
assertEquals("initial", (String)handle.invokeExact(fields));
}
@Test
public void testGetField2() throws Throwable {
Fields fields = new Fields();
MethodHandle handle = Binder
.from(String.class, Fields.class)
.getFieldQuiet(LOOKUP, "instanceField");
assertEquals(MethodType.methodType(String.class, Fields.class), handle.type());
assertEquals("initial", (String)handle.invokeExact(fields));
}
@Test
public void testGetStatic() throws Throwable {
MethodHandle handle = Binder
.from(String.class)
.getStatic(LOOKUP, Fields.class, "staticField");
assertEquals(MethodType.methodType(String.class), handle.type());
assertEquals("initial", (String)handle.invokeExact());
}
@Test
public void testGetStatic2() throws Throwable {
MethodHandle handle = Binder
.from(String.class)
.getStaticQuiet(LOOKUP, Fields.class, "staticField");
assertEquals(MethodType.methodType(String.class), handle.type());
assertEquals("initial", (String)handle.invokeExact());
}
@Test
public void testSetField() throws Throwable {
Fields fields = new Fields();
MethodHandle handle = Binder
.from(void.class, Fields.class, String.class)
.setField(LOOKUP, "instanceField");
assertEquals(MethodType.methodType(void.class, Fields.class, String.class), handle.type());
handle.invokeExact(fields, "modified");
assertEquals("modified", fields.instanceField);
}
@Test
public void testSetField2() throws Throwable {
Fields fields = new Fields();
MethodHandle handle = Binder
.from(void.class, Fields.class, String.class)
.setFieldQuiet(LOOKUP, "instanceField");
assertEquals(MethodType.methodType(void.class, Fields.class, String.class), handle.type());
handle.invokeExact(fields, "modified");
assertEquals("modified", fields.instanceField);
}
@Test
public void testSetStatic() throws Throwable {
try {
MethodHandle handle = Binder
.from(void.class, String.class)
.setStatic(LOOKUP, Fields.class, "staticField");
assertEquals(MethodType.methodType(void.class, String.class), handle.type());
handle.invokeExact("modified");
assertEquals("modified", Fields.staticField);
} finally {
Fields.staticField = "initial";
}
}
@Test
public void testSetStatic2() throws Throwable {
try {
MethodHandle handle = Binder
.from(void.class, String.class)
.setStaticQuiet(LOOKUP, Fields.class, "staticField");
assertEquals(MethodType.methodType(void.class, String.class), handle.type());
handle.invokeExact("modified");
assertEquals("modified", Fields.staticField);
} finally {
Fields.staticField = "initial";
}
}
@Test
public void testNop() throws Throwable {
MethodHandle handle = Binder
.from(void.class, int.class, String.class)
.nop();
assertEquals(MethodType.methodType(void.class, int.class, String.class), handle.type());
try {
handle.invokeExact(1, "foo");
} catch (Throwable t) {
assertTrue("should not reach here", false);
}
}
@Test
public void testThrowException() throws Throwable {
MethodHandle handle = Binder
.from(void.class, BlahException.class)
.throwException();
assertEquals(MethodType.methodType(void.class, BlahException.class), handle.type());
try {
handle.invokeExact(new BlahException());
assertTrue("should not reach here", false);
} catch (BlahException be) {
}
}
@Test
public void testTryFinally() throws Throwable {
MethodHandle post = Binder
.from(void.class, String[].class)
.invokeStatic(LOOKUP, BinderTest.class, "finallyLogic");
MethodHandle handle = Binder
.from(void.class, String[].class)
.tryFinally(post)
.invokeStatic(LOOKUP, BinderTest.class, "setZeroToFoo");
assertEquals(MethodType.methodType(void.class, String[].class), handle.type());
String[] stringAry = new String[1];
handle.invokeExact(stringAry);
assertEquals("foofinally", stringAry[0]);
}
@Test
public void testTryFinally2() throws Throwable {
MethodHandle post = Binder
.from(void.class, String[].class)
.invokeStatic(LOOKUP, BinderTest.class, "finallyLogic");
MethodHandle handle = Binder
.from(void.class, String[].class)
.tryFinally(post)
.invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooAndRaise");
assertEquals(MethodType.methodType(void.class, String[].class), handle.type());
String[] stringAry = new String[1];
try {
handle.invokeExact(stringAry);
assertTrue("should not have reached here", false);
} catch (BlahException re) {
}
assertEquals("foofinally", stringAry[0]);
}
@Test
public void testTryFinally3() throws Throwable {
MethodHandle post = Binder
.from(void.class, String[].class)
.invokeStatic(LOOKUP, BinderTest.class, "finallyLogic");
MethodHandle ignoreException = Binder
.from(void.class, BlahException.class, String[].class)
.nop();
MethodHandle handle = Binder
.from(void.class, String[].class)
.tryFinally(post)
.catchException(BlahException.class, ignoreException)
.invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooAndRaise");
assertEquals(MethodType.methodType(void.class, String[].class), handle.type());
String[] stringAry = new String[1];
try {
handle.invokeExact(stringAry);
} catch (BlahException re) {
assertTrue("should not have reached here", false);
}
assertEquals("foofinally", stringAry[0]);
}
@Test
public void testTryFinallyReturn() throws Throwable {
MethodHandle post = Binder
.from(void.class, String[].class)
.invokeStatic(LOOKUP, BinderTest.class, "finallyLogic");
MethodHandle handle = Binder
.from(int.class, String[].class)
.tryFinally(post)
.invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooReturnInt");
assertEquals(MethodType.methodType(int.class, String[].class), handle.type());
String[] stringAry = new String[1];
assertEquals(1, (int)handle.invokeExact(stringAry));
assertEquals("foofinally", stringAry[0]);
}
@Test
public void testTryFinallyReturn2() throws Throwable {
MethodHandle post = Binder
.from(void.class, String[].class)
.invokeStatic(LOOKUP, BinderTest.class, "finallyLogic");
MethodHandle handle = Binder
.from(int.class, String[].class)
.tryFinally(post)
.invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooReturnIntAndRaise");
assertEquals(MethodType.methodType(int.class, String[].class), handle.type());
String[] stringAry = new String[1];
try {
int x = (int)handle.invokeExact(stringAry);
assertTrue("should not have reached here", false);
} catch (BlahException re) {
}
assertEquals("foofinally", stringAry[0]);
}
@Test
public void testTryFinallyReturn3() throws Throwable {
MethodHandle post = Binder
.from(void.class, String[].class)
.invokeStatic(LOOKUP, BinderTest.class, "finallyLogic");
MethodHandle ignoreException = Binder
.from(int.class, BlahException.class, String[].class)
.drop(0, 2)
.constant(1);
MethodHandle handle = Binder
.from(int.class, String[].class)
.tryFinally(post)
.catchException(BlahException.class, ignoreException)
.invokeStatic(LOOKUP, BinderTest.class, "setZeroToFooReturnIntAndRaise");
assertEquals(MethodType.methodType(int.class, String[].class), handle.type());
String[] stringAry = new String[1];
try {
assertEquals(1, (int)handle.invokeExact(stringAry));
} catch (BlahException be) {
assertTrue("should not have reached here", false);
}
assertEquals("foofinally", stringAry[0]);
}
@Test
public void testArraySet() throws Throwable {
MethodHandle handle = Binder
.from(void.class, Object[].class, int.class, Object.class)
.arraySet();
assertEquals(MethodType.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 testArrayGet() throws Throwable {
MethodHandle handle = Binder
.from(Object.class, Object[].class, int.class)
.arrayGet();
assertEquals(MethodType.methodType(Object.class, Object[].class, int.class), handle.type());
Object[] ary = new Object[] {"foo"};
assertEquals(handle.invokeExact(ary, 0), "foo");
}
@Test
public void testBranch() throws Throwable {
MethodHandle handle = Binder
.from(String.class, String.class)
.branch(
Binder
.from(boolean.class, String.class)
.invokeStatic(LOOKUP, BinderTest.class, "isStringFoo"),
Binder
.from(String.class, String.class)
.invokeStatic(LOOKUP, BinderTest.class, "addBar"),
Binder
.from(String.class, String.class)
.invokeStatic(LOOKUP, BinderTest.class, "addBaz")
);
assertEquals(MethodType.methodType(String.class, String.class), handle.type());
assertEquals("foobar", (String)handle.invokeExact("foo"));
assertEquals("quuxbaz", (String)handle.invokeExact("quux"));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
public static MethodHandle intLongHandle() throws Exception {
return LOOKUP.findStatic(BinderTest.class, "intLong", MethodType.methodType(String.class, int.class, long.class));
}
public String concatVirtual(String a, String b) {
return a + b;
}
public static boolean isStringFoo(String a) {
return a.equals("foo");
}
public static String addBar(String a) {
return a + "bar";
}
public static String addBaz(String a) {
return a + "baz";
}
public static void setZeroToFoo(String[] ary) {
ary[0] = "foo";
}
public static void setZeroToFooAndRaise(String[] ary) throws BlahException {
ary[0] = "foo";
throw new BlahException();
}
public static int setZeroToFooReturnInt(String[] ary) {
ary[0] = "foo";
return 1;
}
public static int setZeroToFooReturnIntAndRaise(String[] ary) throws BlahException {
ary[0] = "foo";
throw new BlahException();
}
public static void finallyLogic(String[] ary) {
ary[0] = ary[0] + "finally";
}
public static String[] varargs(String arg0, String... args) {
return args;
}
public static String varargs(Object... args)
{
return (String) args[0];
}
public static String intLong(int a, long b) {
return "intLong ok";
}
public static class BlahException extends Exception {}
public static class Fields {
public String instanceField = "initial";
public static String staticField = "initial";
}
/**
* Represents a constructable object that's always equal to other constructables.
*/
public static class Constructable {
private final String a, b;
public Constructable(String a, String b) {
this.a = a;
this.b = b;
}
public boolean equals(Object other) {
if (!(other instanceof Constructable)) return false;
Constructable c = (Constructable)other;
return a.equals(c.a) && b.equals(c.b);
}
}
public static MethodHandle mixedHandle() throws Exception {
return LOOKUP.findStatic(BinderTest.class, "mixed", MethodType.methodType(void.class, String.class, int.class, float.class));
}
public static void mixed(String a, int b, float c) {
}
public static String alwaysYahooStatic(String ignored) {
return "yahoo";
}
public String alwaysYahooVirtual(String ignored) {
return "yahoo";
}
}
invokebinder-invokebinder-1.7/src/test/java/com/headius/invokebinder/SignatureTest.java 0000664 0000000 0000000 00000031065 12645741720 0031544 0 ustar 00root root 0000000 0000000 /*
* Copyright 2013 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author headius
*/
public class SignatureTest {
public SignatureTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
/**
* Test of toString method, of class Signature.
*/
@Test
public void testToString() {
assertEquals("(Object obj, int num)String", stringObjectInt.toString());
}
/**
* Test of returning method, of class Signature.
*/
@Test
public void testReturning() {
Signature sig = Signature.returning(String.class);
assertEquals(String.class, sig.type().returnType());
}
/**
* Test of asFold method, of class Signature.
*/
@Test
public void testAsFold() {
Signature sig = Signature
.returning(String.class)
.asFold(Object.class);
assertEquals(Object.class, sig.type().returnType());
}
/**
* Test of appendArg method, of class Signature.
*/
@Test
public void testAppendArg() {
Signature sig = Signature
.returning(String.class)
.appendArg("obj", Object.class);
assertEquals("(Object obj)String", sig.toString());
sig = sig
.appendArg("num", int.class);
assertEquals("(Object obj, int num)String", sig.toString());
}
/**
* Test of prependArg method, of class Signature.
*/
@Test
public void testPrependArg() {
Signature sig = Signature
.returning(String.class)
.appendArg("num", int.class);
assertEquals("(int num)String", sig.toString());
sig = sig
.prependArg("obj", Object.class);
assertEquals("(Object obj, int num)String", sig.toString());
}
/**
* Test of insertArg method, of class Signature.
*/
@Test
public void testInsertArg() {
Signature sig = Signature
.returning(String.class)
.appendArg("obj", Object.class)
.appendArg("num", int.class)
.insertArg(1, "flo", float.class);
assertEquals("(Object obj, float flo, int num)String", sig.toString());
}
@Test
public void testInsertArgBefore() {
Signature sig = Signature
.returning(String.class)
.appendArg("obj", Object.class)
.appendArg("num", int.class)
.insertArg("num", "flo", float.class);
assertEquals("(Object obj, float flo, int num)String", sig.toString());
}
/**
* Test of insertArgs method, of class Signature.
*/
@Test
public void testInsertArgs() {
Signature sig = Signature
.returning(String.class)
.appendArg("obj", Object.class)
.appendArg("num", int.class)
.insertArgs(1, new String[]{"flo", "dub"}, new Class[] {float.class, double.class});
assertEquals("(Object obj, float flo, double dub, int num)String", sig.toString());
}
@Test
public void testInsertArgsBefore() {
Signature sig = Signature
.returning(String.class)
.appendArg("obj", Object.class)
.appendArg("num", int.class)
.insertArgs("num", new String[]{"flo", "dub"}, new Class[] {float.class, double.class});
assertEquals("(Object obj, float flo, double dub, int num)String", sig.toString());
}
/**
* Test of methodType method, of class Signature.
*/
@Test
public void testMethodType() {
assertEquals(MethodType.methodType(String.class, Object.class, int.class), stringObjectInt.type());
}
/**
* Test of argNames method, of class Signature.
*/
@Test
public void testArgNames() {
assertArrayEquals(new String[] {"obj", "num"}, stringObjectInt.argNames());
}
@Test
public void testArgName() {
assertEquals("num", stringObjectInt.appendArg("flo", float.class).argName(1));
Signature oldSig = stringObjectInt;
Signature newSig = oldSig.argName(0, "str");
assertEquals("str", newSig.argName(0));
}
@Test
public void testLastArgName() {
assertEquals("flo", stringObjectInt.appendArg("flo", float.class).lastArgName());
}
@Test
public void testFirstArgName() {
assertEquals("obj", stringObjectInt.appendArg("flo", float.class).firstArgName());
}
@Test
public void testArgOffset() {
assertEquals(1, stringObjectInt.argOffset("num"));
assertEquals(-1, stringObjectInt.argOffset("flo"));
}
@Test
public void testArgOffsets() {
assertEquals(1, stringObjectInt.argOffsets("nu*"));
assertEquals(-1, stringObjectInt.argOffsets("fl."));
}
@Test
public void testArgType() {
assertEquals(int.class, stringObjectInt.appendArg("flo", float.class).argType(1));
Signature oldSig = stringObjectInt;
Signature newSig = oldSig.argType(0, String.class);
assertEquals(String.class, newSig.argType(0));
}
@Test
public void testFirstArgType() {
assertEquals(Object.class, stringObjectInt.appendArg("flo", float.class).firstArgType());
}
@Test
public void testLastArgType() {
assertEquals(float.class, stringObjectInt.appendArg("flo", float.class).lastArgType());
}
/**
* Test of permute method, of class Signature.
*/
@Test
public void testPermute() {
Signature sig = stringObjectInt
.appendArg("flo", float.class)
.appendArg("dub", double.class)
.permute("obj", "dub");
assertEquals("(Object obj, double dub)String", sig.toString());
}
@Test
public void testExclude() {
Signature sig = stringObjectInt
.appendArg("flo", float.class)
.appendArg("dub", double.class)
.exclude("obj", "dub");
assertEquals("(int num, float flo)String", sig.toString());
}
/**
* Test of permuteTo method, of class Signature.
*/
@Test
public void testPermuteWith() throws Throwable {
MethodHandle handle = stringObjectInt
.appendArg("flo", float.class)
.appendArg("dub", double.class)
.permuteWith(stringObjectIntTarget, "obj", "num");
assertEquals(MethodType.methodType(String.class, Object.class, int.class, float.class, double.class), handle.type());
assertEquals("foo1", (String)handle.invokeExact((Object)"foo", 1, 1.0f, 1.0));
}
@Test
public void testPermuteWithSmartHandle() throws Throwable {
SmartHandle target = new SmartHandle(stringObjectInt, stringObjectIntTarget);
SmartHandle permuted = stringObjectInt
.appendArg("flo", float.class)
.appendArg("dub", double.class)
.permuteWith(target);
assertEquals("(Object obj, int num, float flo, double dub)String", permuted.signature().toString());
assertEquals("foo1", permuted.handle().invokeWithArguments("foo", 1, 1.0f, 1.0));
}
@Test
public void testSpreadNamesAndTypes() throws Throwable {
Signature sig = stringObjectAry
.spread(new String[]{"int", "flo"}, Integer.class, Float.class);
assertEquals("(Integer int, Float flo)String", sig.toString());
}
@Test
public void testSpreadNames() throws Throwable {
Signature sig = stringObjectAry
.spread("obj0", "obj1");
assertEquals("(Object obj0, Object obj1)String", sig.toString());
}
@Test
public void testSpreadNameAndCount() throws Throwable {
Signature sig = stringObjectAry
.spread("obj", 2);
assertEquals("(Object obj0, Object obj1)String", sig.toString());
}
/**
* Test of to method, of class Signature.
*/
@Test
public void testTo_Signature() {
int[] permuteInts = stringObjectInt
.appendArg("flo", float.class)
.appendArg("dub", double.class)
.to(stringObjectInt);
assertArrayEquals(new int[] {0, 1}, permuteInts);
}
/**
* Test of to method, of class Signature.
*/
@Test
public void testTo_StringArr() {
int[] permuteInts = stringObjectInt
.appendArg("flo", float.class)
.appendArg("dub", double.class)
.to(".*o.*");
assertArrayEquals(new int[] {0, 2}, permuteInts);
permuteInts = stringObjectInt
.appendArg("flo", float.class)
.appendArg("dub", double.class)
.to("num", "dub");
assertArrayEquals(new int[] {1, 3}, permuteInts);
}
@Test
public void testDropArg() {
Signature newSig = stringObjectInt
.appendArg("flo", float.class)
.dropArg("num");
assertEquals("(Object obj, float flo)String", newSig.toString());
}
@Test
public void testDropArgIndex() {
Signature newSig = stringObjectInt
.appendArg("flo", float.class)
.dropArg(1);
assertEquals("(Object obj, float flo)String", newSig.toString());
}
@Test
public void testDropLast() {
Signature newSig = stringObjectInt
.dropLast();
assertEquals("(Object obj)String", newSig.toString());
newSig = stringObjectInt
.dropLast(2);
assertEquals("()String", newSig.toString());
}
@Test
public void testDropFirst() {
Signature newSig = stringObjectInt
.dropFirst();
assertEquals("(int num)String", newSig.toString());
newSig = stringObjectInt
.dropFirst(2);
assertEquals("()String", newSig.toString());
}
@Test
public void testReplaceArg() {
Signature newSig = stringObjectInt
.replaceArg("obj", "list", List.class);
assertEquals("(List list, int num)String", newSig.toString());
}
@Test
public void testCollect() {
Signature oldSig = Subjects.StringIntegerIntegerIntegerString;
Signature newSig = oldSig.collect("bs", "b.*");
assertEquals(Integer[].class, newSig.argType(1));
assertEquals("bs", newSig.argName(1));
assertEquals(3, newSig.argCount());
assertEquals("c", newSig.argName(2));
oldSig = Subjects.StringIntegerIntegerInteger;
newSig = oldSig.collect("bs", "b.*");
assertEquals(Integer[].class, newSig.argType(1));
assertEquals("bs", newSig.argName(1));
assertEquals(2, newSig.argCount());
}
private static final Signature stringObjectInt = Signature
.returning(String.class)
.appendArg("obj", Object.class)
.appendArg("num", int.class);
private static final Signature stringObjectAry = Signature
.returning(String.class)
.appendArg("objs", Object[].class);
private static final MethodHandle stringObjectIntTarget = Binder
.from(String.class, Object.class, int.class)
.invokeStaticQuiet(MethodHandles.lookup(), SignatureTest.class, "stringObjectIntMethod");
private static String stringObjectIntMethod(Object obj, int num) {
return obj.toString() + num;
}
}
invokebinder-invokebinder-1.7/src/test/java/com/headius/invokebinder/SmartBinderTest.java 0000664 0000000 0000000 00000033365 12645741720 0032022 0 ustar 00root root 0000000 0000000 /*
* Copyright 2013 headius.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.headius.invokebinder;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author headius
*/
public class SmartBinderTest {
public SmartBinderTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
/**
* Test of from method, of class SmartBinder.
*/
@Test
public void testFrom_Signature() throws Throwable {
SmartHandle handle = SmartBinder
.from(Signature.returning(String.class).appendArg("int", int.class))
.invoke(stringInt);
assertEquals("42", (String)handle.handle().invokeExact(42));
}
@Test
public void testDrop() throws Throwable {
Signature oldSig = Subjects.StringIntegerIntegerIntegerString;
SmartHandle handle = SmartBinder.from(oldSig)
.drop("b1")
.drop("b2")
.drop("b3")
.insert(1, "bs", new Integer[]{1, 2, 3})
.invoke(Subjects.StringIntegersStringHandle);
assertEquals("[foo, [1, 2, 3], bar]", (String)handle.handle().invokeExact("foo", new Integer(5), new Integer(6), new Integer(7), "bar"));
}
@Test
public void testDropLast() throws Throwable {
Signature oldSig = Subjects.StringIntegerIntegerIntegerString;
SmartHandle handle = SmartBinder.from(oldSig)
.dropLast(4)
.append("bs", new Integer[]{1, 2, 3})
.append("c", "baz")
.invoke(Subjects.StringIntegersStringHandle);
assertEquals("[foo, [1, 2, 3], baz]", (String)handle.handle().invokeExact("foo", new Integer(5), new Integer(6), new Integer(7), "bar"));
}
@Test
public void testDropFirst() throws Throwable {
Signature oldSig = Subjects.StringIntegerIntegerIntegerString;
SmartHandle handle = SmartBinder.from(oldSig)
.dropFirst(4)
.prepend("bs", new Integer[]{1, 2, 3})
.prepend("a", "baz")
.invoke(Subjects.StringIntegersStringHandle);
assertEquals("[baz, [1, 2, 3], bar]", (String)handle.handle().invokeExact("foo", new Integer(5), new Integer(6), new Integer(7), "bar"));
}
@Test
public void testCollect() throws Throwable {
Signature oldSig = Subjects.StringIntegerIntegerIntegerString;
SmartHandle handle = SmartBinder
.from(oldSig)
.collect("bs", "b.*")
.invoke(Subjects.StringIntegersStringHandle);
assertEquals("[foo, [1, 2, 3], bar]", (String)handle.handle().invokeExact("foo", new Integer(1), new Integer(2), new Integer(3), "bar"));
}
@Test
public void testInvokeStatic() throws Throwable {
SmartHandle handle = SmartBinder
.from(Subjects.StringIntegersString)
.invokeStatic(LOOKUP, Subjects.class, "stringIntegersString");
assertEquals(Subjects.StringIntegersString, handle.signature());
assertEquals(Subjects.StringIntegersString.type(), handle.handle().type());
assertEquals("[foo, [1, 2, 3], bar]", (String)handle.handle().invokeExact("foo", new Integer[]{1,2,3}, "bar"));
handle = SmartBinder
.from(Subjects.StringIntegersString)
.invokeStatic(LOOKUP, Subjects.class, "stringIntegersString");
assertEquals(Subjects.StringIntegersString, handle.signature());
assertEquals(Subjects.StringIntegersString.type(), handle.handle().type());
assertEquals("[foo, [1, 2, 3], bar]", (String)handle.handle().invokeExact("foo", new Integer[]{1,2,3}, "bar"));
}
@Test
public void testInvokeVirtual() throws Throwable {
Subjects subjects = new Subjects();
Signature thisSig = Subjects.StringIntegersString.prependArg("this", Subjects.class);
SmartHandle handle = SmartBinder
.from(thisSig)
.invokeVirtual(LOOKUP, "stringIntegersString2");
assertEquals(thisSig, handle.signature());
assertEquals(thisSig.type(), handle.handle().type());
assertEquals("[foo, [1, 2, 3], bar]", (String)handle.handle().invokeExact(subjects, "foo", new Integer[]{1,2,3}, "bar"));
handle = SmartBinder
.from(thisSig)
.invokeVirtual(LOOKUP, "stringIntegersString2");
assertEquals(thisSig, handle.signature());
assertEquals(thisSig.type(), handle.handle().type());
assertEquals("[foo, [1, 2, 3], bar]", (String)handle.handle().invokeExact(subjects, "foo", new Integer[]{1,2,3}, "bar"));
}
@Test
public void testInsert() throws Throwable {
MethodHandle target = Subjects.concatHandle();
SmartHandle handle = SmartBinder
.from(String.class, "arg0", String.class)
.insert(1, "arg1", "world")
.invoke(target);
assertEquals(MethodType.methodType(String.class, String.class), handle.signature().type());
assertEquals("Hello, world", (String) handle.handle().invokeExact("Hello, "));
MethodHandle target2 = Subjects.concatCharSequenceHandle();
SmartHandle handle2 = SmartBinder
.from(String.class, "arg0", String.class)
.insert(1, "arg1", CharSequence.class, "world")
.invoke(target2);
assertEquals(MethodType.methodType(String.class, String.class), handle2.signature().type());
assertEquals("Hello, world", (String) handle2.handle().invokeExact("Hello, "));
}
@Test
public void testAppend() throws Throwable {
MethodHandle target = Subjects.concatHandle();
SmartHandle handle = SmartBinder
.from(String.class, new String[] {"arg0", "arg1"}, String.class, Object.class)
.append("arg2", "world")
.drop("arg1")
.invoke(target);
assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle.signature().type());
assertEquals("Hello, world", (String) handle.handle().invokeExact("Hello, ", new Object()));
MethodHandle target2 = Subjects.concatCharSequenceHandle();
SmartHandle handle2 = SmartBinder
.from(String.class, new String[] {"arg0", "arg1"}, String.class, Object.class)
.append("arg2", CharSequence.class, "world")
.drop("arg1")
.invoke(target2);
assertEquals(MethodType.methodType(String.class, String.class, Object.class), handle2.signature().type());
assertEquals("Hello, world", (String) handle2.handle().invokeExact("Hello, ", new Object()));
}
@Test
public void testPrepend() throws Throwable {
MethodHandle target = Subjects.concatHandle();
SmartHandle handle = SmartBinder
.from(String.class, new String[]{"arg1", "arg2"}, Object.class, String.class)
.prepend("arg0", "Hello, ")
.drop("arg1")
.invoke(target);
assertEquals(MethodType.methodType(String.class, Object.class, String.class), handle.signature().type());
assertEquals("Hello, world", (String) handle.handle().invokeExact(new Object(), "world"));
MethodHandle target2 = Subjects.concatHandle();
SmartHandle handle2 = SmartBinder
.from(String.class, new String[] {"arg1", "arg2"}, Object.class, String.class)
.prepend("arg0", String.class, "Hello, ")
.drop("arg1")
.invoke(target2);
assertEquals(MethodType.methodType(String.class, Object.class, String.class), handle2.signature().type());
assertEquals("Hello, world", (String) handle2.handle().invokeExact(new Object(), "world"));
}
@Test
public void testCast() throws Throwable {
MethodHandle target = LOOKUP.unreflect(String.class.getMethod("split", String.class));
// cast for virtual call using full static signature
SmartHandle handle = SmartBinder
.from(Object.class, new String[]{"this", "regex"}, Object.class, Object.class)
.cast(String[].class, String.class, String.class)
.invoke(target);
assertArrayEquals(new String[]{"foo", "bar"}, (String[])(Object)handle.handle().invokeExact((Object)"foo,bar", (Object)","));
// cast for virtual call using ret, this, args
handle = SmartBinder
.from(new Signature(Object.class, Object.class, new Class[]{Object.class}, "this", "regex"))
.castVirtual(String[].class, String.class, new Class[]{String.class})
.invoke(target);
assertArrayEquals(new String[]{"foo", "bar"}, (String[])(Object)handle.handle().invokeExact((Object)"foo,bar", (Object)","));
}
@Test
public void testFilter() throws Throwable {
MethodHandle target = Subjects.concatHandle();
MethodHandle filter = MethodHandles.insertArguments(Subjects.concatHandle(), 1, "goodbye");
MethodHandle handle = SmartBinder
.from(String.class, new String[]{"arg1", "arg2"}, String.class, String.class)
.filter("arg.*", filter)
.invoke(target).handle();
assertEquals(MethodType.methodType(String.class, String.class, String.class), handle.type());
assertEquals("foogoodbyebargoodbye", (String)handle.invokeExact("foo", "bar"));
}
@Test
public void testIdentity() throws Throwable {
MethodHandle handle = SmartBinder
.from(String.class, "i", int.class)
.fold("s", stringInt)
.dropLast()
.identity()
.handle();
assertEquals(MethodType.methodType(String.class, int.class), handle.type());
assertEquals("15", (String)handle.invokeExact(15));
}
@Test
public void testFoldStatic() throws Throwable {
MethodHandle handle = SmartBinder
.from(Subjects.StringIntegerIntegerInteger)
.foldStatic("x", Subjects.class, "foldStringIntegerIntegerInteger")
.drop("a")
.drop("b1")
.drop("b2")
.drop("b3")
.invokeStatic(MethodHandles.lookup(), Subjects.class, "upperCase")
.handle();
assertEquals("FORTY_TWO", (String)handle.invokeExact("foo",
Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)));
}
@Test
public void testFoldVirtual() throws Throwable {
MethodHandle handle = SmartBinder
.from(Subjects.StringIntegerIntegerInteger)
.prepend("this", new Subjects())
.foldVirtual("x", "foldVirtualStringIntegerIntegerInteger")
.drop("this")
.drop("a")
.drop("b1")
.drop("b2")
.drop("b3")
.invokeStatic(MethodHandles.lookup(), Subjects.class, "upperCase")
.handle();
assertEquals("FORTY_TWO", (String)handle.invokeExact("foo",
Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)));
}
@Test
public void testFoldVirtualWithLookup() throws Throwable {
MethodHandle handle = SmartBinder
.from(Subjects.StringIntegerIntegerInteger)
.prepend("this", new Subjects())
.foldVirtual("x", MethodHandles.lookup(), "foldVirtualStringIntegerIntegerInteger")
.drop("this")
.drop("a")
.drop("b1")
.drop("b2")
.drop("b3")
.invokeStatic(MethodHandles.lookup(), Subjects.class, "upperCase")
.handle();
assertEquals("FORTY_TWO", (String)handle.invokeExact("foo",
Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)));
}
@Test
public void testPrintSignature() throws Throwable {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
MethodHandle handle = SmartBinder
.from(Subjects.StringIntegerIntegerInteger)
.foldStatic("x", Subjects.class, "foldStringIntegerIntegerInteger")
.drop("a").printSignature(ps)
.drop("b1")
.drop("b2")
.drop("b3").printSignature(ps)
.invokeStatic(MethodHandles.lookup(), Subjects.class, "upperCase")
.handle();
String result = baos.toString();
assertEquals(
"(String x, Integer b1, Integer b2, Integer b3)String\n" +
"(String x)String\n",
result);
}
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
private static final MethodHandle stringInt = Binder
.from(String.class, int.class)
.invokeStaticQuiet(LOOKUP, Integer.class, "toString");
} invokebinder-invokebinder-1.7/src/test/java/com/headius/invokebinder/Subjects.java 0000664 0000000 0000000 00000005735 12645741720 0030532 0 ustar 00root root 0000000 0000000 package com.headius.invokebinder;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
/**
* Created by headius on 1/25/14.
*/
public class Subjects {
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
public static final Signature StringIntegerIntegerIntegerString = Signature
.returning(String.class)
.appendArg("a", String.class)
.appendArg("b1", Integer.class)
.appendArg("b2", Integer.class)
.appendArg("b3", Integer.class)
.appendArg("c", String.class);
public static final Signature StringIntegerIntegerInteger = Signature
.returning(String.class)
.appendArg("a", String.class)
.appendArg("b1", Integer.class)
.appendArg("b2", Integer.class)
.appendArg("b3", Integer.class);
public static final Signature StringIntegersString = Signature
.returning(String.class)
.appendArg("a", String.class)
.appendArg("bs", Integer[].class)
.appendArg("c", String.class);
public static final MethodHandle StringIntegersStringHandle = Binder
.from(String.class, String.class, Integer[].class, String.class)
.invokeStaticQuiet(LOOKUP, Subjects.class, "stringIntegersString");
public static final MethodHandle StringIntegersHandle = Binder
.from(String.class, String.class, Integer[].class)
.invokeStaticQuiet(LOOKUP, Subjects.class, "stringIntegers");
public static String stringIntegersString(String a, Integer[] bs, String c) {
return Arrays.deepToString(new Object[]{a, bs, c});
}
public static String stringIntegers(String a, Integer[] bs) {
return Arrays.deepToString(new Object[]{a, bs});
}
public static MethodHandle concatHandle() throws Exception {
return LOOKUP.findStatic(Subjects.class, "concatStatic", MethodType.methodType(String.class, String.class, String.class));
}
public static MethodHandle concatCharSequenceHandle() throws Exception {
return LOOKUP.findStatic(Subjects.class, "concatStatic", MethodType.methodType(String.class, String.class, CharSequence.class));
}
public static String concatStatic(String a, String b) {
return a + b;
}
public static String concatStatic(String a, CharSequence b) {
return a + b;
}
public String stringIntegersString2(String a, Integer[] bs, String c) {
return Arrays.deepToString(new Object[]{a, bs, c});
}
public static String foldStringIntegerIntegerInteger(String a, Integer b1, Integer b2, Integer b3) {
return "forty_two";
}
public String foldVirtualStringIntegerIntegerInteger(String a, Integer b1, Integer b2, Integer b3) {
return "forty_two";
}
public static String upperCase(String x) {
return x.toUpperCase();
}
}