diff --git a/.circleci/config.yml b/.circleci/config.yml
deleted file mode 100644
index 37ed748..0000000
--- a/.circleci/config.yml
+++ /dev/null
@@ -1,56 +0,0 @@
-version: 2.1
-
-orbs:
- github-maven-deploy: github-maven-deploy/github-maven-deploy@1.2.0
-
-mvn-build-test-command: &mvn-build-test-command
- mvn-build-test-command: mvn verify -Dmaven.javadoc.skip=true -Djacoco.skip=true -Dlicense.skip=true
-
-mvn-deploy-command: &mvn-deploy-command
- mvn-deploy-command: |
- mvn -s .circleci/maven-release-settings.xml clean deploy -DdeployAtEnd=true -DperformRelease=true -DskipTests -Dspotbugs.skip=true -Denforcer.skip=true -Djacoco.skip=true
- mvn license:remove
- context: RELEASE_PROFILE_BBOTTEMA
-
-workflows:
- workflow:
- jobs:
- - github-maven-deploy/build-and-test:
- <<: *mvn-build-test-command
- filters:
- branches:
- only: master
-
- - github-maven-deploy/approve-deploy-patch-version:
- type: approval
- requires:
- - github-maven-deploy/build-and-test
- - github-maven-deploy/approve-deploy-minor-version:
- type: approval
- requires:
- - github-maven-deploy/build-and-test
- - github-maven-deploy/approve-deploy-major-version:
- type: approval
- requires:
- - github-maven-deploy/build-and-test
- - github-maven-deploy/approve-deploy-as-is-version:
- type: approval
- requires:
- - github-maven-deploy/build-and-test
-
- - github-maven-deploy/deploy-patch-version:
- requires:
- - github-maven-deploy/approve-deploy-patch-version
- <<: *mvn-deploy-command
- - github-maven-deploy/deploy-minor-version:
- requires:
- - github-maven-deploy/approve-deploy-minor-version
- <<: *mvn-deploy-command
- - github-maven-deploy/deploy-major-version:
- requires:
- - github-maven-deploy/approve-deploy-major-version
- <<: *mvn-deploy-command
- - github-maven-deploy/deploy-as-is-version:
- requires:
- - github-maven-deploy/approve-deploy-as-is-version
- <<: *mvn-deploy-command
diff --git a/.circleci/maven-release-settings.xml b/.circleci/maven-release-settings.xml
deleted file mode 100644
index f478962..0000000
--- a/.circleci/maven-release-settings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- ossrh
- ${env.SERVER_OSSRH_USERNAME}
- ${env.SERVER_OSSRH_PASSWORD}
-
-
-
-
-
- gpg
-
- gpg
- ${env.GPG_PASSPHRASE}
-
-
-
-
- gpg
-
-
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 6a45d03..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-/.idea
-/javadoc
-/target
-*.iml
\ No newline at end of file
diff --git a/Documentation.md b/Documentation.md
new file mode 100644
index 0000000..b7668ce
--- /dev/null
+++ b/Documentation.md
@@ -0,0 +1,34 @@
+## Introducing Java Reflection ##
+
+Java Reflection provides a small package with nifty Java reflection methods.
+
+Aside from a variety of utility functions, this library mainly aims to ease method/constructor lookups, using value conversions, such as autoboxing, auto casting, but also commons value conversions (such as Boolean to String and many more).
+
+Normal JDK method matching through reflection is very strict on the exact argument class types, but with this Java Reflection Library, this is much easier and more robust (and performs better).
+
+The main reason this project is available as open source is because it is a dependency of the [Swift Socket Server](https://code.google.com/p/swift-socket-server/) project, yet merited a project of its own.
+
+### Documentation ###
+
+Because of the size and nature of this little project, about four utility classes with only `static` methods, I will refer to the JavaDoc for all documentation.
+
+[JReflect](http://java-reflection.googlecode.com/svn/trunk/javadoc/users/org/codemonkey/javareflection/JReflect.html) |
+[ValueConverter](http://java-reflection.googlecode.com/svn/trunk/javadoc/users/org/codemonkey/javareflection/ValueConverter.html) |
+[FieldUtils](http://java-reflection.googlecode.com/svn/trunk/javadoc/users/org/codemonkey/javareflection/FieldUtils.html) |
+[ExternalClassLoader](http://java-reflection.googlecode.com/svn/trunk/javadoc/users/org/codemonkey/javareflection/ExternalClassLoader.html)
+
+### What's inside ###
+
+#### Main features ####
+
+ * an advanced utility class that finds and invokes methods/constructors based on a given list of values (optionally converting the values to the right type)
+ * a conversion class that is able to convert common value type to a different type (`boolean` to `Character` for example)
+ * an easy way to find an object's fields, optionally including setters/getters, restricted by a number of criteria (such as: should have a getter method, should be a `public` field etc.)
+ * an (experimental, but tested) ClassLoader that is able to resort to manually compile .class files and load them on the fly
+
+#### Extra features ####
+
+ * a method that returns the autoboxed version of a value
+ * a convenience method that assign a value to an object's field directly
+ * a method that determines what the smallest `Number` type is that can hold a list of given number values of various types without losing precision
+ * various utility methods
\ No newline at end of file
diff --git a/LICENSE-2.0.txt b/LICENSE-2.0.txt
deleted file mode 100644
index d645695..0000000
--- a/LICENSE-2.0.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
- 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.
diff --git a/NOTICE.txt b/NOTICE.txt
deleted file mode 100644
index daa17f0..0000000
--- a/NOTICE.txt
+++ /dev/null
@@ -1,11 +0,0 @@
- =========================================================================
- == NOTICE file for use with the Apache License, Version 2.0 ==
- =========================================================================
-
- Java Reflection, copyright 2009-2020 Benny Bottema
-
- This product uses no commercial products.
-
- This product uses the following external (Open Source) libraries in the deployed code:
-
- - Two partial classes from Apache Commons Lang 2.5 (NumberUtils.isNumber, StringUtils.capitalize)
\ No newline at end of file
diff --git a/ProjectHome.md b/ProjectHome.md
new file mode 100644
index 0000000..1281d30
--- /dev/null
+++ b/ProjectHome.md
@@ -0,0 +1,20 @@
+# Java Reflection #
+
+**Java Reflection provides a small package with nifty reflection features that will help with finding constructors, methods and value conversions**.
+
+The main reason this project is available as open source is because it is a dependency of the [Swift Socket Server](https://code.google.com/p/swift-socket-server/) project, yet merited a project of its own.
+
+Main features:
+
+ * an advanced utility class that finds and invokes methods/constructors based on a given list of values (optionally converting the values to the right type)
+ * a conversion class that is able to convert common value type to a different type (`boolean` to `Character` for example)
+ * an easy way to find an object's fields, optionally including setters/getters, restricted by a number of criteria (such as: should have a getter method, should be a `public` field etc.)
+ * an (experimental, but tested) ClassLoader that is able to resort to manually compile .class files and load them on the fly
+
+Extra features:
+
+ * a method that returns the autoboxed version of a value
+ * a convenience method that assign a value to an object's field directly
+ * a method that determines what the smallest `Number` type is that can hold a list of given number values of various types without losing precision
+ * various utility methods
+
diff --git a/README.md b/README.md
deleted file mode 100644
index dc197f9..0000000
--- a/README.md
+++ /dev/null
@@ -1,194 +0,0 @@
-[](LICENSE-2.0.txt)
-[](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.bbottema%22%20AND%20a%3A%22java-reflection%22)
-[](http://www.javadoc.io/doc/com.github.bbottema/java-reflection)
-[](https://www.codacy.com/app/b-bottema/java-reflection)
-
-# java-reflection
-*java-reflection* is an advanced toolbox for finding compatible methods, constructors, annotations and converting values.
-
-It defines utilities on Class level, Method level, Bean level, Package level, Type level and General utilities.
-
-In additions, it provides an advanced conversion framework, that uses Dijkstra's graph to find the most efficient conversion route,
-through multiple converters if a direct one is not available. It contains many built in converters and allows for easy extension.
-
-```
-
- com.github.bbottema
- java-reflection
- 4.1.1
-
-```
-
-v4.1.1 (05-March-2025)
-
-- some confusion in the release history, but this is now the correct version number
-
-
-v4.1.0 (18-January-2024 )
-
-- Updated Jakarta Activation to Angus Activation package
-
-
-v4.0.0 (26-December-2021)
-
-- Updated to Java 8 and fixed recent log4j security issue
-- Updated to Jakarta 2.0.1
-
-
-v3.13.1 (15-June-2020)
-
-- Made zipping method parameters and arguments more flexible
-
-
-v3.13.0 (17-November-2019)
-
-- Added converter support for String to Date yyyy-MM-dd[ HH:mm]
-
-
-v3.12.0 (4-November-2019)
-
-- For simple class lookups, In addition to java.lang, also try the packages java.util and java.math
-
-
-v3.11.1 - v3.11.3 (29-October-2019 - 1-November-2019)
-
-- 3.11.3: Solved an NullPointerException in a collectMethods method
-- 3.11.2: recompiled so the line numbers are correct with the released sources (due to license boilerplate added at the wrong time)
-- 3.11.1: ClassUtils.collectMethods now returns methods define on implemented interfaces as well
-
-
-v3.11.0 (27-October-2019)
-
-- Added support for UUID conversion
-- The Jakarta Activation framework is now an explicit dependency
-
-
-v3.10.1 (21-October-2019)
-
-- Made locateClass a little bit more user friendly by deferring return type T
-
-
-v3.10.0 (28-September-2019)
-
-- Added methods for finding parameters by annotations type
-- Moved to Intellij @Nullability annotations
-- Added license boilerplate code in Maven build script
-- Solved a bunch of static anlayses warnings
-- Improved how compatibility work when passing null-arguments as argument lists for locating constructors/methods
-
-
-v3.9.5 (3-June-2019)
-
-- Added method to check if a class has a method with a given name
-
-
-v3.9.4 (27-May-2019)
-
-- Allow null-values when invoking setter
-
-
-v3.9.3 (10-May-2019)
-
-- Added API for checking method compatibility based on actual arguments rather than by types only
-- Added helper method to zip method parameters with their respective actual arguments
-- Made the LookupMode arguments of type Set rather than EnumSet, so they can be made unmodifiable
-- Added convenience method for returning the verify and return the only method in a findMethods result
-
-
-v3.9.2 (30-April-2019)
-
-- Added API to easily invoke bean setters / getters or methods
-
-
-v3.9.1 (27-April-2019)
-
-- Added convencience method to return the first method for a specified name
-- Added method that returns an annotation of a specified type from a list
-- Added method that returns an annotation of a specified type from an array
-- Fixed visibility modifier on a public API
-
-
-v3.9.0 (18-Januari-2019)
-
-- Added support for bean-like methods defined on interfaces
-
-
-v3.8.1 - v3.8.5 (13-October-2018 - 8-Januari-2019)
-
-- Added support for same-type converters
-- Performance update: implemented cache for generateComptibleSignatureLists
-- Fixed Incompatible type exception if a number is outside of Byte or Short range
-- Incompatible type exceptions are now gathered in case a conversion ultimately failed
-
-
-v3.8.0 (9-October-2018)
-
-- Added File based converters to InputStream, DataSource and byte[]
-- Fixed problem with conversion candidates failing during actual conversions, so now we try all candidates rather than just the first one
-- Fixed nullability analysis issue
-
-
-v3.7.0 (6-October-2018)
-
-- Added API for find declared Generic types in inheritance chains
-
-
-v3.6.0 (4-October-2018)
-
-- Added API for resolving field values
-- Fixed API for searching fields. Now fields of any visibility can be resolved
-
-
-v3.5.1 (1-October-2018)
-
-- Added overloaded version of MethodUtils.findMatchingMethods(..) that also supports Collection in addition to varargs...
-- Fixed name based type matching to properly work with arrays vs varargs...
-
-
-v3.5.0 (30-September-2018)
-
-- Made method collection facilities in ClassUtil much more robust by allowing any combination of method modifiers to find methods for rather than just
- a boolean "publicOnly". This includes modifiers other than for visibility as well.
-
-
-v3.4.0 (26-September-2018)
-
-- Added BeanUtils API to verify if a given Method is a bean setter / getter
-
-
-v3.3.0 (26-September-2018)
-
-- More robust class location facility
-- Support any custom classloader for locating classes
-
-
-v3.2.1 (24-September-2018)
-
-- Optimized recursive code and implemented some caches
-
-
-v3.2.0 (21-September-2018)
-
-- Added alternative lookup method for Methods based on type names rather than types
-- Streamlines ClassUtils API a bit
-
-
-v3.1.0 (21-September-2018)
-
-Complete overhaul:
-- Conversion now works with graph-based path finding resolution to find all possible conversion paths
-- Converters can now be added by third parties
-- fixed a bug with the cache not working properly
-- restructured classes and packages so it makes a lot more sense
-
-
-v2.x.x (28-August-2018)
-
-- Converted to Java 7 and added spotbugs
-- Resolved a bunch of warnings
-- Removed dependencies on external libraries
-
-
-v1.0 (13-August-2011)
-
-Initial upload
\ No newline at end of file
diff --git a/RELEASE.txt b/RELEASE.txt
deleted file mode 100644
index 9608d13..0000000
--- a/RELEASE.txt
+++ /dev/null
@@ -1,177 +0,0 @@
-https://github.com/bbottema/java-reflection
-
-
-RELEASE NOTES Java Reflection
-
-v4.1.1 (05-March-2025)
-
-- some confusion in the release history, but this is now the correct version number
-
-v4.1.0 (18-January-2024)
-
-- Updated Jakarta Activation to Angus Activation package
-
-
-v4.0.0 (26-December-2021)
-
-- Updated to Java 8 and fixed recent log4j security issue
-- Updated to Jakarta 2.0.1
-
-
-v3.13.1 (15-June-2020)
-
-- Made zipping method parameters and arguments more flexible
-
-
-v3.13.0 (17-November-2019)
-
-- Added converter support for String to Date yyyy-MM-dd[ HH:mm]
-
-
-v3.12.0 (4-November-2019)
-
-- For simple class lookups, In addition to java.lang, also try the packages java.util and java.math
-
-
-v3.11.1 - v3.11.3 (29-October-2019 - 1-November-2019)
-
-- 3.11.3: Solved an NullPointerException in a collectMethods method
-- 3.11.2: recompiled so the line numbers are correct with the released sources (due to license boilerplate added at the wrong time)
-- 3.11.1: ClassUtils.collectMethods now returns methods define on implemented interfaces as well
-
-
-v3.11.0 (27-October-2019)
-
-- Added support for UUID conversion
-- The Jakarta Activation framework is now an explicit dependency
-
-
-v3.10.1 (21-October-2019)
-
-- Made locateClass a little bit more user friendly by deferring return type T
-
-
-v3.10.0 (28-September-2019)
-
-- Added methods for finding parameters by annotations type
-- Moved to Intellij @Nullability annotations
-- Added license boilerplate code in Maven build script
-- Solved a bunch of static anlayses warnings
-- Improved how compatibility work when passing null-arguments as argument lists for locating constructors/methods
-
-
-v3.9.5 (3-June-2019)
-
-- Added method to check if a class has a method with a given name
-
-
-v3.9.4 (27-May-2019)
-
-- Allow null-values when invoking setter
-
-
-v3.9.3 (10-May-2019)
-
-- Added API for checking method compatibility based on actual arguments rather than by types only
-- Added helper method to zip method parameters with their respective actual arguments
-- Made the LookupMode arguments of type Set rather than EnumSet, so they can be made unmodifiable
-- Added convenience method for returning the verify and return the only method in a findMethods result
-
-
-v3.9.2 (30-April-2019)
-
-- Added API to easily invoke bean setters / getters or methods
-
-
-v3.9.1 (27-April-2019)
-
-- Added convencience method to return the first method for a specified name
-- Added method that returns an annotation of a specified type from a list
-- Added method that returns an annotation of a specified type from an array
-- Fixed visibility modifier on a public API
-
-
-v3.9.0 (18-Januari-2019)
-
-- Added support for bean-like methods defined on interfaces
-
-
-v3.8.1 - v3.8.5 (13-October-2018 - 8-Januari-2019)
-
-- Added support for same-type converters
-- Performance update: implemented cache for generateComptibleSignatureLists
-- Fixed Incompatible type exception if a number is outside of Byte or Short range
-- Incompatible type exceptions are now gathered in case a conversion ultimately failed
-
-
-v3.8.0 (9-October-2018)
-
-- Added File based converters to InputStream, DataSource and byte[]
-- Fixed problem with conversion candidates failing during actual conversions, so now we try all candidates rather than just the first one
-- Fixed nullability analysis issue
-
-
-v3.7.0 (6-October-2018)
-
-- Added API for find declared Generic types in inheritance chains
-
-
-v3.6.0 (4-October-2018)
-
-- Added API for resolving field values
-- Fixed API for searching fields. Now fields of any visibility can be resolved
-
-
-v3.5.1 (1-October-2018)
-
-- Added overloaded version of MethodUtils.findMatchingMethods(..) that also supports Collection in addition to varargs...
-- Fixed name based type matching to properly work with arrays vs varargs...
-
-
-v3.5.0 (30-September-2018)
-
-- Made method collection facilities in ClassUtil much more robust by allowing any combination of method modifiers to find methods for rather than just
- a boolean "publicOnly". This includes modifiers other than for visibility as well.
-
-
-v3.4.0 (26-September-2018)
-
-- Added BeanUtils API to verify if a given Method is a bean setter / getter
-
-
-v3.3.0 (26-September-2018)
-
-- More robust class location facility
-- Support any custom classloader for locating classes
-
-
-v3.2.1 (24-September-2018)
-
-- Optimized recursive code and implemented some caches
-
-
-v3.2.0 (21-September-2018)
-
-- Added alternative lookup method for Methods based on type names rather than types
-- Streamlines ClassUtils API a bit
-
-
-v3.1.0 (21-September-2018)
-
-Complete overhaul:
-- Conversion now works with graph-based path finding resolution to find all possible conversion paths
-- Converters can now be added by third parties
-- fixed a bug with the cache not working properly
-- restructured classes and packages so it makes a lot more sense
-
-
-v2.x.x (28-August-2018)
-
-- Converted to Java 7 and added spotbugs
-- Resolved a bunch of warnings
-- Removed dependencies on external libraries
-
-
-v1.0 (13-August-2011)
-
-Initial upload
\ No newline at end of file
diff --git a/how to release.txt b/how to release.txt
deleted file mode 100644
index 20373d0..0000000
--- a/how to release.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-Prerequisite:
-
-You need GPG installed (comes along with GIT installation in the \bin folder) and you need to create a keyring, used for signing artifacts.
-If you have an existing key, simply import it:
-
-gpg --allow-secret-key-import --import .gpg
-
-That, or you can install one of the binaries to import the key, from here: https://www.gnupg.org/download/index.html
-
-To release:
-
- 1. update release notes and github readme page (don't commit)
- 2. remove SNAPSHOT version
- 3. mvn -DperformRelease=true clean deploy
- (set password in settings.xml or use local pgp key password, for which the public key must have been sent to a public key server,
- eg: gpg --keyserver hkp://keyserver.ubuntu.com --send-keys 05AC6403)
- server needed in settings.xml (see below)
- 4. Go to https://oss.sonatype.org and release the artifact so it is submitted to Maven Central
- 5. add new SNAPSHOT version and commit everything
-
-maven's settings.xml:
-
-
- ossrh
- sonatype user
- sonatype password
-
-
-To have a global gpg password so that it will use that automatically:
-
-
-
- gpg
-
- gpg
- letmein
-
-
-
-
- gpg
-
\ No newline at end of file
diff --git a/lib/commons-lang-2.5.jar b/lib/commons-lang-2.5.jar
deleted file mode 100644
index ae491da..0000000
Binary files a/lib/commons-lang-2.5.jar and /dev/null differ
diff --git a/lib/junit-4.8.1.jar b/lib/junit-4.8.1.jar
deleted file mode 100644
index 524cd65..0000000
Binary files a/lib/junit-4.8.1.jar and /dev/null differ
diff --git a/pom.xml b/pom.xml
deleted file mode 100644
index c953eb2..0000000
--- a/pom.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
- 4.0.0
-
-
- com.github.bbottema
- standard-project-parent
- 1.0.42
-
-
- java-reflection
- jar
- Java Reflection
- 4.1.1
- Java Reflection provides a small package with nifty reflection features that will help with finding constructors, methods and value conversions
- https://github.com/bbottema/java-reflection
- 2011
-
-
- scm:git:git://github.com/bbottema/java-reflection.git
- scm:git:git@github.com:bbottema/java-reflection.git
- https://github.com/bbottema/java-reflection
-
-
-
- GitHub Issues
- https://github.com/bbottema/java-reflection/issues
-
-
-
-
- org.jetbrains
- annotations
- 23.1.0
- provided
-
-
-
- org.eclipse.angus
- angus-activation
- 2.0.2
-
-
- org.projectlombok
- lombok
- 1.18.32
- provided
-
-
-
\ No newline at end of file
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
deleted file mode 100644
index ec8851b..0000000
--- a/spotbugs-exclude.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/main/java/org/bbottema/javareflection/BeanUtils.java b/src/main/java/org/bbottema/javareflection/BeanUtils.java
deleted file mode 100644
index 5b1f15c..0000000
--- a/src/main/java/org/bbottema/javareflection/BeanUtils.java
+++ /dev/null
@@ -1,312 +0,0 @@
-package org.bbottema.javareflection;
-
-import lombok.experimental.UtilityClass;
-import org.bbottema.javareflection.util.commonslang25.StringUtils;
-import org.bbottema.javareflection.model.FieldWrapper;
-import org.bbottema.javareflection.model.InvokableObject;
-import org.bbottema.javareflection.valueconverter.IncompatibleTypeException;
-import org.bbottema.javareflection.valueconverter.ValueConversionHelper;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.*;
-import java.util.regex.Pattern;
-
-import static java.util.EnumSet.allOf;
-import static java.util.EnumSet.of;
-import static java.util.regex.Pattern.compile;
-import static org.bbottema.javareflection.BeanUtils.BeanRestriction.YES_SETTER;
-import static org.bbottema.javareflection.BeanUtils.BeanRestriction.YES_GETTER;
-
-/**
- * A {@link Field} shorthand utility class used to collect fields from classes meeting Java Bean restrictions/requirements.
- *
- * With this utility class you can perform field lookups, by combining lookup restriction criteria.
- *
- * Example
- * "find all fields on a class Apple, not looking at its super classes, which should be protected, have a getter method, but not a setter
- * method"
- *
- *
- *
- * @see #collectFields(Class, Class, EnumSet, EnumSet)
- */
-@UtilityClass
-public final class BeanUtils {
-
- /**
- * Determines what visibility modifiers a field is allowed to have in {@link BeanUtils#collectFields(Class, Class, EnumSet, EnumSet)}.
- */
- public enum Visibility {
- /**
- * Visibility flag that corresponds with java's keyword private.
- */
- PRIVATE(Modifier.PRIVATE),
- /**
- * Visibility flag that corresponds with java's visibility modifier default (package protected).
- */
- DEFAULT(-1), // no Java equivalent
- /**
- * Visibility flag that corresponds with java's keyword protected.
- */
- PROTECTED(Modifier.PROTECTED),
- /**
- * Visibility flag that corresponds with java's keyword public.
- */
- PUBLIC(Modifier.PUBLIC);
-
- private final int modifierFlag;
-
- Visibility(final int modifierFlag) {
- this.modifierFlag = modifierFlag;
- }
- }
-
- /**
- * Indicates whether a field needs a Bean setter or getter, exactly none or any combination thereof. Determines what kind of fields are
- * potential collection candidates.
- */
- public enum BeanRestriction {
- /**
- * Restriction flag that indicates a getter method is required.
- */
- YES_GETTER,
- /**
- * Restriction flag that indicates a setter method is required.
- */
- YES_SETTER,
- /**
- * Restriction flag that indicates no setter must be available.
- */
- NO_SETTER,
- /**
- * Restriction flag that indicates a getter must be available.
- */
- NO_GETTER
- }
-
- /**
- * Verifies is a given method occurs as setter or getter in the declaring class chain. Lookup works by finding actual properties with
- * their respective getters/setters that follow bean convention.
- *
- * Note that this is a strict lookup and interface methods are not considered bean methods. To include interfaces and their methods,
- * use {@link #isBeanMethod(Method, Class, EnumSet, boolean)} with checkBeanLikeForInterfaces set to {@code true}.
- *
- * Lookup can be configured to check only against specific visibility.
- *
- * @param method The method to match against getters/setters of a certain visibility
- * @param boundaryMarker The last class or interface implementing class that methods are matched against. Can
- * be used to prevent matching methods on a super class.
- * @param visibility A set of visibility requirements (ie. {@link Visibility#PROTECTED} indicates a *field* for which getter/setter are checked
- * is allowed to have protected visibility). Note: the visibility modifiers for methods are ignored.
- * @return Whether given method is a setter / getter within given restriction boundaries.
- */
- @SuppressWarnings({"unused", "WeakerAccess"})
- public static boolean isBeanMethod(final Method method, final Class> boundaryMarker,
- final EnumSet visibility) {
- return isBeanMethod(method, boundaryMarker, visibility, false);
- }
-
- /**
- * @return Same as {@link #isBeanMethod(Method, Class, EnumSet)}, but may consider methods declared on interfaces as well.
- */
- @SuppressWarnings("WeakerAccess")
- public static boolean isBeanMethod(Method method, Class> boundaryMarker,
- EnumSet visibility, boolean checkBeanLikeForInterfaces) {
- return method.getDeclaringClass().isInterface()
- ? checkBeanLikeForInterfaces && methodIsBeanlike(method)
- : isBeanMethodForField(method, boundaryMarker, visibility);
- }
-
- private static boolean isBeanMethodForField(Method method, Class> boundaryMarker, EnumSet visibility) {
- Map, List> fields = collectFields(method.getDeclaringClass(), boundaryMarker, visibility,
- EnumSet.noneOf(BeanRestriction.class));
- for (List fieldWrappers : fields.values()) {
- for (FieldWrapper fieldWrapper : fieldWrappers) {
- if (method.equals(fieldWrapper.getGetter()) || method.equals(fieldWrapper.getSetter())) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Determines if the method could be a bean method by looking just at its name, parameters and presence of return type.
- *
- * @return True, is the method starts with set/get/is, has exactly one parameter and in case of
- * a primitive boolean the method should start with "isAbc"
- */
- @SuppressWarnings("WeakerAccess")
- public static boolean methodIsBeanlike(Method method) {
- final Pattern SET_PATTERN = compile("set[A-Z].*?");
- final Pattern GET_PATTERN = compile("get[A-Z].*?");
- final Pattern IS_PATTERN = compile("is[A-Z].*?");
-
- final String name = method.getName();
- final int paramCount = method.getParameterTypes().length;
- final Class> rt = method.getReturnType();
-
- return
- (rt == boolean.class && IS_PATTERN.matcher(name).matches() && paramCount == 0) ||
- (rt != void.class && rt != boolean.class && GET_PATTERN.matcher(name).matches() && paramCount == 0) ||
- (rt == void.class && SET_PATTERN.matcher(name).matches() && paramCount == 1);
- }
-
- /**
- * Returns a pool of {@link Field} wrappers including optional relevant setter/getter methods, collected from the given class tested
- * against the given visibility and Bean restriction requirements.
- *
- * The returned fields are mapped against the classes they were found on, since field names can be declared multiple times with the same
- * name.
- *
- * @param _class The class (and chain) to harvest fields from.
- * @param boundaryMarker The last class or interface implementing class that fields are collected from. Can
- * be used to prevent finding fields on a super class.
- * @param visibility A set of visibility requirements (ie. {@link Visibility#PROTECTED} indicates a field is allowed to have
- * protected visibility).
- * @param beanRestrictions A set of Bean restriction requirements indicating a field should or shouldn't have a setter, getter or both.
- * @return A Map per class in the chain with the fields declared by that class.
- * @see #meetsVisibilityRequirements(Field, EnumSet)
- * @see #resolveBeanProperty(Field, EnumSet)
- */
- @SuppressWarnings("WeakerAccess")
- @NotNull
- public static LinkedHashMap, List> collectFields(final Class> _class, final Class> boundaryMarker,
- final EnumSet visibility, final EnumSet beanRestrictions) {
- final LinkedHashMap, List> fields = new LinkedHashMap<>();
- final Field[] allFields = _class.getDeclaredFields();
- final List filteredFields = new LinkedList<>();
- for (final Field field : allFields) {
- if (meetsVisibilityRequirements(field, visibility)) {
- final FieldWrapper property = resolveBeanProperty(field, beanRestrictions);
- if (property != null) {
- filteredFields.add(property);
- }
- }
- }
- fields.put(_class, filteredFields);
- // determine if we need to look deeper
- final List> interfaces = Arrays.asList(_class.getInterfaces());
- if (!_class.equals(boundaryMarker) && !interfaces.contains(boundaryMarker)) {
- fields.putAll(collectFields(_class.getSuperclass(), boundaryMarker, visibility, beanRestrictions));
- }
- return fields;
- }
-
- /**
- * Determines if the visibility modifiers of a given {@link Field} is included in the set of flags.
- *
- * @param field The field who's visibility modifiers we want to test.
- * @param visibility List of {@link Visibility} flags to test against.
- * @return Whether a given field has one of the specified visibility flags.
- */
- static boolean meetsVisibilityRequirements(final Field field, final EnumSet visibility) {
- final int m = field.getModifiers();
-
- for (Visibility visibilityModifier : visibility) {
- if (visibilityModifier != Visibility.DEFAULT) {
- if ((m & visibilityModifier.modifierFlag) != 0) {
- return true;
- }
- } else {
- if (!Modifier.isPrivate(m) && !Modifier.isProtected(m) && !Modifier.isPublic(m)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Determines if a given Field meets the specified Bean restriction requirements and returns the field as a BeanProperty
- * with optional getter/setter.
- *
- * @param field The field to test.
- * @param beanRestrictions The Bean restrictions to apply (should/shouldn't have setter/getter).
- * @return Whether the field fits the restrictions.
- */
- @Nullable
- static FieldWrapper resolveBeanProperty(final Field field, final EnumSet beanRestrictions) {
- if (beanRestrictions.containsAll(EnumSet.of(BeanRestriction.NO_GETTER, BeanRestriction.YES_GETTER)) //
- || beanRestrictions.containsAll(EnumSet.of(BeanRestriction.NO_SETTER, BeanRestriction.YES_SETTER))) {
- throw new IllegalArgumentException("cannot both include and exclude a setter/getter requirement");
- }
-
- // since PropertyUtilsBean#getPropertyDescriptors(...) doesn't detect setters without getters (Bean convention)
- // we'll just find setter/getters manually
- final String setterName = "set" + StringUtils.capitalize(field.getName());
- final String getterName;
- if (field.getType().equals(boolean.class)) {
- getterName = "is" + StringUtils.capitalize(field.getName());
- } else {
- getterName = "get" + StringUtils.capitalize(field.getName());
- }
- final Set> iWriteMethod = MethodUtils.findSimpleCompatibleMethod(field.getDeclaringClass(), setterName, field.getType());
- final Set> iReadMethod = MethodUtils.findSimpleCompatibleMethod(field.getDeclaringClass(), getterName);
-
- if (!((!iReadMethod.isEmpty() && beanRestrictions.contains(BeanRestriction.NO_GETTER)) //
- || (iReadMethod.isEmpty() && beanRestrictions.contains(BeanRestriction.YES_GETTER)) //
- || (!iWriteMethod.isEmpty() && beanRestrictions.contains(BeanRestriction.NO_SETTER)) //
- || (iWriteMethod.isEmpty() && beanRestrictions.contains(BeanRestriction.YES_SETTER)))) {
- Method readMethod = !iReadMethod.isEmpty() ? iReadMethod.iterator().next().getMethod() : null;
- Method writeMethod = !iWriteMethod.isEmpty() ? iWriteMethod.iterator().next().getMethod() : null;
- return new FieldWrapper(field, readMethod, writeMethod);
- } else {
- return null;
- }
- }
-
- /**
- * Calls the setter for the first field in the inheritance chain that matches given fieldName.
- * Attempts to convert the value in case the type is incorrect.
- *
- * @return The actual value used in the bean setter.
- */
- @SuppressWarnings("ConstantConditions")
- @Nullable
- static public Object invokeBeanSetter(Object o, String fieldName, @Nullable Object value) {
- for (List fieldWrappers : collectFields(o.getClass(), Object.class, allOf(Visibility.class), of(YES_SETTER)).values()) {
- for (FieldWrapper fieldWrapper : fieldWrappers) {
- if (fieldWrapper.getField().getName().equals(fieldName) ) {
- Object assignedValue = value;
- try {
- MethodUtils.invokeMethodSimple(fieldWrapper.getSetter(), o, value);
- } catch (final IllegalArgumentException ie) {
- try {
- assignedValue = ValueConversionHelper.convert(value, fieldWrapper.getField().getType());
- } catch (IncompatibleTypeException e) {
- throw new RuntimeException(new NoSuchMethodException(e.getMessage()));
- }
- MethodUtils.invokeMethodSimple(fieldWrapper.getSetter(), o, assignedValue);
- }
- return assignedValue;
- }
- }
- }
- throw new RuntimeException(new NoSuchMethodException("Bean setter for " + fieldName));
- }
-
- /**
- * Calls the getter for the first field in the inheritance chain that matches given fieldName.
- *
- * @see #collectFields(Class, Class, EnumSet, EnumSet)
- */
- @SuppressWarnings("ConstantConditions")
- static public Object invokeBeanGetter(Object o, String fieldName) {
- for (List fieldWrappers : collectFields(o.getClass(), Object.class, allOf(Visibility.class), of(YES_GETTER)).values()) {
- for (FieldWrapper fieldWrapper : fieldWrappers) {
- if (fieldWrapper.getField().getName().equals(fieldName) ) {
- return MethodUtils.invokeMethodSimple(fieldWrapper.getGetter(), o);
- }
- }
- }
- throw new RuntimeException(new NoSuchMethodException("Bean getter for " + fieldName));
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/bbottema/javareflection/ClassUtils.java b/src/main/java/org/bbottema/javareflection/ClassUtils.java
deleted file mode 100644
index 29dbb92..0000000
--- a/src/main/java/org/bbottema/javareflection/ClassUtils.java
+++ /dev/null
@@ -1,342 +0,0 @@
-package org.bbottema.javareflection;
-
-import lombok.experimental.UtilityClass;
-import org.bbottema.javareflection.model.MethodModifier;
-import org.bbottema.javareflection.util.ExternalClassLoader;
-import org.bbottema.javareflection.valueconverter.IncompatibleTypeException;
-import org.bbottema.javareflection.valueconverter.ValueConversionHelper;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.LinkedHashMap;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
-import static org.bbottema.javareflection.LookupCaches.CLASS_CACHE;
-import static org.bbottema.javareflection.util.MiscUtil.trustedNullableCast;
-
-/**
- * Utility with convenience methods that operate on the class level.
- *
- *
With this helper class you can locate and/or load classes. An advanced Class lookup ({@link #locateClass(String, boolean,
- * ClassLoader)}), that allows a full scan (to try all
- * packages known) and an optional {@link ExternalClassLoader} instance that is able to actually compile a .java file on the fly and load its compile
- * .class file
- *
create a new instance while handling all the exceptions
- *
find fields or assign values to fields, using casting, autoboxing or type conversions
- *
simply give back a list of field / method names
- *
- */
-@UtilityClass
-@SuppressWarnings("WeakerAccess")
-public final class ClassUtils {
-
- /**
- * Searches the JVM and optionally all of its packages
- *
- * @param className The name of the class to locate.
- * @param fullscan Whether a full scan through all available java packages is required.
- * @param classLoader Optional user-provided classloader.
- * @return The Class reference if found or null otherwise.
- */
- @Nullable
- @SuppressWarnings({"WeakerAccess", "unchecked"})
- public static Class locateClass(final String className, final boolean fullscan, @Nullable final ClassLoader classLoader) {
- final String cacheKey = className + fullscan;
- if (CLASS_CACHE.containsKey(cacheKey)) {
- return (Class) CLASS_CACHE.get(cacheKey);
- }
- Class> _class;
- if (fullscan) {
- _class = locateClass(className, null, classLoader);
- } else {
- // try standard package used for most common classes
- _class = locateClass(className, "java.lang", classLoader);
- if (_class == null) {
- _class = locateClass(className, "java.util", classLoader);
- }
- if (_class == null) {
- _class = locateClass(className, "java.math", classLoader);
- }
- }
- CLASS_CACHE.put(cacheKey, _class);
- return (Class) _class;
- }
-
- @Nullable
- @SuppressWarnings({"WeakerAccess", "unchecked"})
- public static Class locateClass(final String className, @Nullable final String inPackage, @Nullable final ClassLoader classLoader) {
- final String cacheKey = className + inPackage;
- if (CLASS_CACHE.containsKey(cacheKey)) {
- return (Class) CLASS_CACHE.get(cacheKey);
- }
-
- Class> _class = locateClass(className, classLoader);
-
- if (_class == null) {
- _class = PackageUtils.scanPackagesForClass(className, inPackage, classLoader);
- }
-
- CLASS_CACHE.put(cacheKey, _class);
- return (Class) _class;
- }
-
- /**
- * This function dynamically tries to locate a class. First it searches the class-cache list, then it tries to get it from the Virtual Machine
- * using {@code Class.forName(String)}.
- *
- * @param fullClassName The Class that needs to be found.
- * @param classLoader Optional user-provided classloader.
- * @return The {@code Class} object found from cache or VM.
- */
- @SuppressWarnings({"WeakerAccess", "unchecked"})
- @Nullable
- public static Class locateClass(final String fullClassName, @Nullable final ClassLoader classLoader) {
- try {
- Class> _class = null;
- if (classLoader != null) {
- _class = classLoader.loadClass(fullClassName);
- }
- if (_class == null) {
- _class = Class.forName(fullClassName);
- }
- return (Class) _class;
- } catch (final ClassNotFoundException e) {
- return null;
- }
- }
-
- /**
- * Simply calls {@link Class#newInstance()} and hides the exception handling boilerplate code.
- *
- * @param _class The datatype for which we need to create a new instance of.
- * @param Type used to parameterize the return instance.
- * @return A new parameterized instance of the given type.
- */
- @NotNull
- @SuppressWarnings("WeakerAccess")
- public static T newInstanceSimple(final Class _class) {
- try {
- return ConstructorFactory.obtainConstructor(_class).newInstance();
- } catch (SecurityException e) {
- throw new RuntimeException("unable to invoke parameterless constructor; security problem", e);
- } catch (InstantiationException e) {
- throw new RuntimeException("unable to complete instantiation of object", e);
- } catch (IllegalAccessException e) {
- throw new RuntimeException("unable to access parameterless constructor", e);
- } catch (InvocationTargetException e) {
- throw new RuntimeException("unable to invoke parameterless constructor", e);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("unable to find parameterless constructor (not public?)", e);
- }
- }
-
- // Workaround: mockito does not support mocking Class.class, so getConstructor() cannot be mocked and we mock this factory method instead.
- static class ConstructorFactory {
- static Constructor obtainConstructor(Class _class) throws NoSuchMethodException {
- return _class.getConstructor();
- }
- }
-
- /**
- * Gets value from the field returned by {@link #solveField(Object, String)}.;
- */
- @Nullable
- @SuppressWarnings("WeakerAccess")
- public static T solveFieldValue(final Object object, final String fieldName) {
- final Field field = solveField(object, fieldName);
- if (field == null) {
- throw new RuntimeException(new NoSuchFieldException());
- }
- field.setAccessible(true);
- try {
- return trustedNullableCast(field.get(object));
- } catch (IllegalAccessException e) {
- throw new RuntimeException("Was unable to retrieve value from field %s", e);
- }
- }
-
- /**
- * Delegates to {@link #solveField(Class, String)} by using the class of given object object or if object itself if it ss a class.
- */
- @Nullable
- @SuppressWarnings("WeakerAccess")
- public static Field solveField(final Object object, final String fieldName) {
- return object.getClass().equals(Class.class)
- ? solveField((Class>) object, fieldName) // Java static field
- : solveField(object.getClass(), fieldName); // Java instance field
- }
-
- /**
- * Returns a field from the given Class that goes by the name of fieldName. Will search for fields on implemented interfaces and superclasses.
- *
- * @param _class The reference to the Class to fetch the field from.
- * @param fieldName The identifier or name of the member field/property.
- * @return The value of the Field.
- */
- @Nullable
- @SuppressWarnings("WeakerAccess")
- public static Field solveField(final Class> _class, final String fieldName) {
- Field resolvedField = null;
- try {
- resolvedField = _class.getDeclaredField(fieldName);
- } catch (NoSuchFieldException e) {
- for (int i = 0; resolvedField == null && i < _class.getInterfaces().length; i++) {
- resolvedField = solveField(_class.getInterfaces()[i], fieldName);
- }
- for (Class> superclass = _class.getSuperclass(); resolvedField == null && superclass != null; superclass = superclass.getSuperclass()) {
- resolvedField = solveField(superclass, fieldName);
- }
- }
- return resolvedField;
- }
-
- /**
- * Assigns a value to a field id on the given object o. If a simple assignment fails, a common conversion will be
- * attempted.
- *
- * @param o The object to find the field on.
- * @param property The name of the field we're assigning the value to.
- * @param value The value to assign to the field, may be converted to the field's type through common conversion.
- * @return The actual value that was assigned (the original or the converted value).
- * @throws IllegalAccessException Thrown by {@link Field#set(Object, Object)}
- * @throws NoSuchFieldException Thrown if the {@link Field} could not be found, even after trying to convert the value to the target type.
- * @see ValueConversionHelper#convert(Object, Class)
- */
- @Nullable
- @SuppressWarnings("WeakerAccess")
- public static Object assignToField(final Object o, final String property, final Object value) throws IllegalAccessException, NoSuchFieldException {
- final Field field = solveField(o, property);
- if (field != null) {
- field.setAccessible(true);
- Object assignedValue = value;
- try {
- field.set(o, value);
- } catch (final IllegalArgumentException ie) {
- try {
- assignedValue = ValueConversionHelper.convert(value, field.getType());
- } catch (IncompatibleTypeException e) {
- throw new NoSuchFieldException(e.getMessage());
- }
- field.set(o, assignedValue);
- }
- return assignedValue;
- } else {
- throw new NoSuchFieldException();
- }
- }
-
- /**
- * Returns a list of names that represent the fields on an Object.
- *
- * @param subject The Object who's properties/fields need to be reflected.
- * @return A list of names that represent the fields on the given Object.
- */
- @NotNull
- @SuppressWarnings("WeakerAccess")
- public static Collection collectPropertyNames(final Object subject) {
- final Collection properties = new LinkedHashSet<>();
- final Field[] fields = subject.getClass().getFields();
- for (final Field f : fields) {
- properties.add(f.getName());
- }
- return properties;
- }
-
- /**
- * @return Returns the result of {@link #collectMethods(Class, Class, EnumSet)} mapped to the method names.
- */
- @SuppressWarnings("WeakerAccess")
- public static Set collectMethodNames(Class> dataType, Class> boundaryMarker, EnumSet methodModifiers) {
- Set methodNames = new HashSet<>();
- for (Method m : collectMethods(dataType, boundaryMarker, methodModifiers)) {
- methodNames.add(m.getName());
- }
- return methodNames;
- }
-
- /**
- * @return The result of {@link #collectMethodsMappingToName(Class, Class, EnumSet)} filtered on method name.
- */
- @SuppressWarnings("WeakerAccess")
- public static List collectMethodsByName(final Class> type, Class> boundaryMarker, EnumSet methodModifiers, final String methodName) {
- LinkedHashMap> methodsByName = collectMethodsMappingToName(type, boundaryMarker, methodModifiers);
- return methodsByName.containsKey(methodName) ? methodsByName.get(methodName) : new ArrayList();
- }
-
- /**
- * @return Whether {@link #collectMethodsMappingToName(Class, Class, EnumSet)} contains a method with the given name.
- */
- @SuppressWarnings("WeakerAccess")
- public static boolean hasMethodByName(final Class> type, Class> boundaryMarker, EnumSet methodModifiers, final String methodName) {
- LinkedHashMap> methodsByName = collectMethodsMappingToName(type, boundaryMarker, methodModifiers);
- return methodsByName.containsKey(methodName) && !methodsByName.get(methodName).isEmpty();
- }
-
- /**
- * @return The first result of {@link #collectMethodsByName(Class, Class, EnumSet, String)}.
- * Note: methods are ordered in groups (see {@link #collectMethods(Class, Class, EnumSet)})).
- */
- @Nullable
- @SuppressWarnings("WeakerAccess")
- public static Method findFirstMethodByName(final Class> type, Class> boundaryMarker, EnumSet methodModifiers, final String methodName) {
- List methods = collectMethodsByName(type, boundaryMarker, methodModifiers, methodName);
- return methods.isEmpty() ? null : methods.iterator().next();
- }
-
- /**
- * @return The result of {@link #collectMethods(Class, Class, EnumSet)} filtered on method name,
- * ordered in groups (see {@link #collectMethods(Class, Class, EnumSet)})).
- */
- @SuppressWarnings("WeakerAccess")
- public static LinkedHashMap> collectMethodsMappingToName(Class> type, Class> boundaryMarker, EnumSet methodModifiers) {
- LinkedHashMap> methodsMappedToName = new LinkedHashMap<>();
- for (Method method : collectMethods(type, boundaryMarker, methodModifiers)) {
- if (!methodsMappedToName.containsKey(method.getName())) {
- methodsMappedToName.put(method.getName(), new ArrayList());
- }
- methodsMappedToName.get(method.getName()).add(method);
- }
- return methodsMappedToName;
- }
-
- /**
- * Returns a list of names that represent the methods on an Object.
- *
- * Methods are ordered by their declaring type in the inheritance chain, but unordered for methods of the same type.
- * In other words, considering type A, B and C each with methods 1, 2 and 3, the methods might be ordered as follows:
- * {@code [A2,A1,B1,B2,C2,C1]}.
- *
- * @param methodModifiers List of method modifiers that will match any method that has one of them.
- * @param boundaryMarker Optional type to limit (including) how far back up the inheritance chain we go for discovering methods.
- * @return Returns a list with methods, either {@link Method}s.
- */
- @SuppressWarnings("WeakerAccess")
- public static List collectMethods(Class> dataType, Class> boundaryMarker, EnumSet methodModifiers) {
- final List allMethods = new ArrayList<>();
-
- for (Method declaredMethod : dataType.getDeclaredMethods()) {
- if (MethodModifier.meetsModifierRequirements(declaredMethod, methodModifiers)) {
- allMethods.add(declaredMethod);
- }
- }
-
- for (Class> implementedInterface : dataType.getInterfaces()) {
- allMethods.addAll(collectMethods(implementedInterface, boundaryMarker, methodModifiers));
- }
-
- if (dataType != boundaryMarker && dataType.getSuperclass() != null) {
- allMethods.addAll(collectMethods(dataType.getSuperclass(), boundaryMarker, methodModifiers));
- }
- return allMethods;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/bbottema/javareflection/LookupCaches.java b/src/main/java/org/bbottema/javareflection/LookupCaches.java
deleted file mode 100644
index ab90dbf..0000000
--- a/src/main/java/org/bbottema/javareflection/LookupCaches.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package org.bbottema.javareflection;
-
-import org.bbottema.javareflection.model.InvokableObject;
-import org.bbottema.javareflection.model.LookupMode;
-import org.bbottema.javareflection.util.ArrayKey;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * For internal use for improving repeated lookup performances.
- */
-public class LookupCaches {
-
- /**
- * {@link Class} cache optionally used when looking up classes with {@link ClassUtils#locateClass(String, boolean, ClassLoader)}.
- */
- final static Map> CLASS_CACHE = new HashMap<>();
-
- /**
- * {@link Method} cache categorized by owning Classes (since several owners can have a method with the same name and signature).
- * Methods are stored based on Method reference along with their unique signature (per owner), so multiple methods on one owner with
- * the same name can coexist.
- *
- * This cache is being maintained to reduce lookup times when trying to find signature compatible Java methods. The possible signature
- * combinations using autoboxing and/or automatic common conversions can become very large (7000+ with only three parameters) and can become a
- * real problem. The more frequently a method is being called the larger the performance gain, especially for methods with long parameter lists
- *
- * @see "MethodUtils.addMethodToCache(Class, String, Set, Class[])"
- * @see "MethodUtils#getMethodFromCache(Class, String, Class[])"
- */
- final static Map, Map[], Set>>> METHOD_CACHE = new LinkedHashMap<>();
-
- static final Map, Set>> CACHED_REGISTERED_COMPATIBLE_TARGET_TYPES = new HashMap<>();
- static final Map, Set>> CACHED_COMPATIBLE_TARGET_TYPES = new HashMap<>();
- private static final Map, Map[]>>> CACHED_COMPATIBLE_TYPE_LISTS = new HashMap<>();
-
- @SuppressWarnings({"unused"})
- public static void resetCache() {
- CLASS_CACHE.clear();
- METHOD_CACHE.clear();
- CACHED_REGISTERED_COMPATIBLE_TARGET_TYPES.clear();
- CACHED_COMPATIBLE_TARGET_TYPES.clear();
- CACHED_COMPATIBLE_TYPE_LISTS.clear();
- }
-
- @Nullable
- static List[]> getCachedCompatibleSignatures(Set lookupMode, ArrayKey arrayKey) {
- final Map[]>> cachedCompatibleSignatures = CACHED_COMPATIBLE_TYPE_LISTS.get(lookupMode);
- if (cachedCompatibleSignatures != null) {
- return cachedCompatibleSignatures.get(arrayKey);
- }
- return null;
- }
-
- @NotNull
- static List[]> addCompatiblesignaturesToCache(Set lookupMode, ArrayKey arrayKey, List[]> compatibleTypeLists) {
- Map[]>> cachedCompatibleSignatures = CACHED_COMPATIBLE_TYPE_LISTS.get(lookupMode);
- if (cachedCompatibleSignatures == null) {
- CACHED_COMPATIBLE_TYPE_LISTS.put(lookupMode, cachedCompatibleSignatures = new HashMap<>());
- }
- cachedCompatibleSignatures.put(arrayKey, compatibleTypeLists);
- return compatibleTypeLists;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/bbottema/javareflection/MethodUtils.java b/src/main/java/org/bbottema/javareflection/MethodUtils.java
deleted file mode 100644
index 48a7276..0000000
--- a/src/main/java/org/bbottema/javareflection/MethodUtils.java
+++ /dev/null
@@ -1,600 +0,0 @@
-package org.bbottema.javareflection;
-
-import lombok.experimental.UtilityClass;
-import org.bbottema.javareflection.model.InvokableObject;
-import org.bbottema.javareflection.model.LookupMode;
-import org.bbottema.javareflection.model.MethodModifier;
-import org.bbottema.javareflection.model.MethodParameter;
-import org.bbottema.javareflection.util.MiscUtil;
-import org.bbottema.javareflection.valueconverter.IncompatibleTypeException;
-import org.bbottema.javareflection.valueconverter.ValueConversionHelper;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.slf4j.Logger;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.*;
-
-import static java.lang.String.format;
-import static org.bbottema.javareflection.LookupCaches.METHOD_CACHE;
-import static org.bbottema.javareflection.TypeUtils.containsAnnotation;
-import static org.bbottema.javareflection.util.MiscUtil.trustedCast;
-import static org.bbottema.javareflection.util.MiscUtil.trustedNullableCast;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * This reflection tool is designed to perform advanced method or constructor lookups,
- * using a combination of {@link LookupMode} strategies.
- *
- * It tries to find a constructor of a given datatype, with a given argument
- * datatypelist, where types do not have to match formal types (auto-boxing, supertypes, implemented interfaces and type conversions are allowed as
- * they are included in the lookup cycles). This expanded version tries a simple call first (exact match, which is provided natively by the Java) and
- * when this fails, it generates a list of datatype arrays (signatures) with all possible versions of any type in the original list possible, and
- * combinations thereof.
- *
- * Observe the following (trivial) example:
- *
- *
- * interface Foo {
- * void foo(Double value, Fruit fruit, char c);
- * }
- * abstract class A implements Foo {
- * }
- * abstract class B extends A {
- * }
- *
- * ClassUtils.findCompatibleJavaMethod(B.class, "foo", EnumSet.allOf(LookupMode.class), double.class, Pear.class, String.class)}
- *
- *
- * In the above example, the method foo will be found by finding all methods named "Foo" on the interfaces implemented by supertype A,
- * and then foo's method signature will be matched using autoboxing on the double type, a cast to the Fruit supertype for
- * the Pear type and finally by attempting a common conversion from String to char. This will give you a Java
- * {@link Method}, but you won't be able to invoke it if it was found using a less strict lookup than one with a simple exact match. There are two
- * ways to do this: use {@link #invokeCompatibleMethod(Object, Class, String, Object...)} instead or perform the conversion yourself using {@link
- * ValueConversionHelper#convert(Object[], Class[], boolean)} prior to invoking the method. ValueConverter.convert(args,
- * method.getParameterTypes()).
- *
- * A reverse lookup is also possible: given an ordered list of possible types, is a given Method compatible?
- *
- * Because this lookup is potentially very expensive, a cache is present to store lookup results.
- */
-@UtilityClass
-public final class MethodUtils {
-
- private static final Logger LOGGER = getLogger(MethodUtils.class);
-
- /**
- * Delegates to {@link Method#invoke(Object, Object...)} while converting checked exceptions into runtime
- * exceptions.
- */
- @Nullable
- @SuppressWarnings({"unchecked"})
- public static T invokeMethodSimple(final Method method, @Nullable final Object subject, final Object... args) {
- try {
- return (T) method.invoke(subject, args);
- } catch (SecurityException e) {
- throw new RuntimeException("unable to invoke method; security problem", e);
- } catch (IllegalAccessException e) {
- throw new RuntimeException("unable to access method", e);
- } catch (InvocationTargetException e) {
- throw new RuntimeException("unable to invoke method", e);
- }
- }
-
- /**
- * Locates a method on an Object using serveral searchmodes for optimization. First of all a {@link Method} cache is being maintained to quickly
- * fetch heavily used methods. If not cached before and if a simple search (autoboxing and supertype casts) fails a more complex search is done
- * where all interfaces are searched for the method as well. If this fails as well, this method will try to autoconvert the types of the arguments
- * and find a matching signature that way.
- *
- * @param context The object to call the method from (can be null).
- * @param datatype The class to find the method on.
- * @param identifier The name of the method to locate.
- * @param args A list of [non-formal] arguments.
- * @return The return value of the invoke method, if successful.
- * @throws NoSuchMethodException Thrown by {@link #findCompatibleMethod(Class, String, Set, Class...)}.
- * @throws IllegalArgumentException Thrown by {@link Method#invoke(Object, Object...)}.
- * @throws IllegalAccessException Thrown by {@link Method#invoke(Object, Object...)}.
- * @throws InvocationTargetException Thrown by {@link Method#invoke(Object, Object...)}.
- */
- @SuppressWarnings({"WeakerAccess"})
- @Nullable
- public static T invokeCompatibleMethod(@Nullable final Object context, final Class> datatype, final String identifier, final Object... args)
- throws NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
- // determine the signature we want to find a compatible java method for
- final Class>[] parameterSignature = TypeUtils.collectTypes(args);
-
- // setup lookup procedure starting with simple search mode
- Set lookupMode = EnumSet.of(LookupMode.AUTOBOX, LookupMode.CAST_TO_SUPER);
- Set> iMethods;
-
- // try to find a compatible Java method using various lookup modes
- try {
- iMethods = findCompatibleMethod(datatype, identifier, lookupMode, parameterSignature);
- } catch (final NoSuchMethodException e1) {
- try {
- // moderate search mode
- lookupMode.add(LookupMode.CAST_TO_INTERFACE);
- iMethods = findCompatibleMethod(datatype, identifier, lookupMode, parameterSignature);
- } catch (final NoSuchMethodException e2) {
- try {
- // limited conversions searchmode
- lookupMode.add(LookupMode.COMMON_CONVERT);
- iMethods = findCompatibleMethod(datatype, identifier, lookupMode, parameterSignature);
- } catch (NoSuchMethodException e3) {
- // full searchmode
- lookupMode.add(LookupMode.SMART_CONVERT);
- iMethods = findCompatibleMethod(datatype, identifier, lookupMode, parameterSignature);
- }
- }
- }
-
- for (InvokableObject iMethod : iMethods) {
- iMethod.getMethod().setAccessible(true);
-
- try {
- Object[] convertedArgs = ValueConversionHelper.convert(args, iMethod.getCompatibleSignature(), false);
- return trustedNullableCast(iMethod.getMethod().invoke(context, convertedArgs));
- } catch (IncompatibleTypeException e) {
- // keep trying conversion candidates...
- }
- }
-
- LOGGER.error(format("Was unable to find a suitable method on %s for the parameter signature %s", datatype, Arrays.toString(parameterSignature)));
- throw new NoSuchMethodException();
- }
-
- /**
- * Locates and invokes a {@link Constructor}using {@link #invokeConstructor(Class, Class[], Object[])}
- *
- * @param Used to parameterize the returned object so that the caller doesn't need to cast.
- * @param datatype The class to find the constructor for.
- * @param args A list of [non-formal] arguments.
- * @return The instantiated object of class datatype.
- * @throws IllegalAccessException Thrown by {@link #invokeConstructor(Class, Class[], Object[])}.
- * @throws InvocationTargetException Thrown by {@link #invokeConstructor(Class, Class[], Object[])}.
- * @throws InstantiationException Thrown by {@link #invokeConstructor(Class, Class[], Object[])}.
- * @throws NoSuchMethodException Thrown by {@link #invokeConstructor(Class, Class[], Object[])}.
- * @see java.lang.reflect.Constructor#newInstance(Object[])
- */
- @SuppressWarnings({"UnusedReturnValue", "WeakerAccess", "unused"})
- @NotNull
- public static T invokeCompatibleConstructor(final Class datatype, final Object... args) throws NoSuchMethodException,
- IllegalAccessException, InvocationTargetException, InstantiationException {
- final Class>[] parameterList = TypeUtils.collectTypes(args);
- return invokeConstructor(datatype, parameterList, args);
- }
-
- /**
- * Locates and invokes a {@link Constructor}, using a customized typelist. Avoids dynamically trying to find correct parameter type list. Can also
- * be used to force up/down casting (ie. passing a specific type of List into a generic type)
- *
- * @param Used to parameterize the returned object so that the caller doesn't need to cast.
- * @param datatype The class to find the constructor for.
- * @param parameterSignature The typelist used to find correct constructor.
- * @param args A list of [non-formal] arguments.
- * @return The instantiated object of class datatype.
- * @throws IllegalAccessException Thrown by {@link Constructor#newInstance(Object...)}.
- * @throws InvocationTargetException Thrown by {@link Constructor#newInstance(Object...)}.
- * @throws InstantiationException Thrown by {@link Constructor#newInstance(Object...)}.
- * @throws NoSuchMethodException Thrown by {@link #findCompatibleConstructor(Class, Set, Class...)}.
- * @see java.lang.reflect.Constructor#newInstance(Object[])
- */
- @SuppressWarnings("WeakerAccess")
- @NotNull
- public static T invokeConstructor(final Class datatype, final Class>[] parameterSignature, final Object[] args) throws NoSuchMethodException,
- IllegalAccessException, InvocationTargetException, InstantiationException {
- // setup lookup procedure
- Set lookupMode = EnumSet.of(LookupMode.AUTOBOX, LookupMode.CAST_TO_SUPER);
- Set> iConstructors;
-
- // try to find a compatible Java constructor
- try {
- iConstructors = findCompatibleConstructor(datatype, lookupMode, parameterSignature);
- } catch (final NoSuchMethodException e1) {
- try {
- lookupMode.add(LookupMode.CAST_TO_INTERFACE);
- iConstructors = findCompatibleConstructor(datatype, lookupMode, parameterSignature);
- } catch (final NoSuchMethodException e2) {
- try {
- lookupMode.add(LookupMode.COMMON_CONVERT);
- iConstructors = findCompatibleConstructor(datatype, lookupMode, parameterSignature);
- } catch (final NoSuchMethodException e3) {
- lookupMode.add(LookupMode.SMART_CONVERT);
- iConstructors = findCompatibleConstructor(datatype, lookupMode, parameterSignature);
- }
- }
- }
-
- for (InvokableObject iConstructor : iConstructors) {
- try {
- Object[] convertedArgs = ValueConversionHelper.convert(args, iConstructor.getCompatibleSignature(), false);
- return trustedCast(iConstructor.getMethod().newInstance(convertedArgs));
- } catch (IncompatibleTypeException e) {
- // keep trying conversion candidates...
- }
- }
-
- LOGGER.error(format("Was unable to find a suitable constructor on %s for the parameter signature %s", datatype, Arrays.toString(parameterSignature)));
- throw new NoSuchMethodException();
- }
-
- /**
- * Tries to find a {@link Constructor} of a given type, with a given typelist, where types do not match due to formal types.
- * This expanded version tries a simple call first and when it fails, it generates a list of type arrays with all possible (un)wraps of any type
- * in the original list possible, and combinations thereof.
- *
- * @param Used to parameterize the returned constructor.
- * @param datatype The class to get the constructor from.
- * @param lookupMode Flag indicating the search steps that need to be done.
- * @param signature The list of types as specified by the user.
- * @return The constructor if found, otherwise exception is thrown.
- * @exception NoSuchMethodException Thrown when the {@link Constructor} could not be found on the data type, even after performing optional
- * conversions.
- */
- @SuppressWarnings({"WeakerAccess"})
- public static Set> findCompatibleConstructor(final Class datatype, final Set lookupMode, final Class>... signature)
- throws NoSuchMethodException {
- // first try to find the constructor in the method cache
- Set> iConstructors = getConstructorFromCache(datatype, datatype.getName(), signature);
- if (iConstructors != null) {
- return iConstructors;
- } else {
- iConstructors = new HashSet<>();
-
- try {
- // try standard call
- iConstructors.add(new InvokableObject(datatype.getConstructor(signature), signature, signature));
- } catch (final NoSuchMethodException e) {
- for (final Class>[] compatibleSignature : TypeUtils.generateCompatibleTypeLists(lookupMode, signature)) {
- try {
- iConstructors.add(new InvokableObject(datatype.getConstructor(compatibleSignature), signature, compatibleSignature));
- } catch (final NoSuchMethodException x) {
- // do nothing
- }
- }
- }
- }
-
- if (!iConstructors.isEmpty()) {
- return addMethodToCache(datatype, datatype.getName(), iConstructors, signature);
- } else {
- throw new NoSuchMethodException();
- }
- }
-
- /**
- * Delegates to {@link #findCompatibleMethod(Class, String, Set, Class...)}, using strict lookupmode (no autoboxing, casting etc.) and
- * optional signature parameters.
- *
- * @param datatype The class to get the constructor from.
- * @param methodName The name of the method to retrieve from the class.
- * @param signature The list of types as specified by the user.
- * @return null in case of a NoSuchMethodException exception.
- * @see #findCompatibleMethod(Class, String, Set, Class...)
- */
- @NotNull
- @SuppressWarnings("WeakerAccess")
- public static Set> findSimpleCompatibleMethod(final Class> datatype, final String methodName, final Class>... signature) {
- try {
- return findCompatibleMethod(datatype, methodName, EnumSet.noneOf(LookupMode.class), signature);
- } catch (final NoSuchMethodException e) {
- return new HashSet<>();
- }
- }
-
- /**
- * Delegates to {@link #findCompatibleMethod(Class, String, Set, Class[])}, with the types of the given arguments extracted using {@link TypeUtils#collectTypes(Object[])}.
- */
- public static Set> findCompatibleMethod(final Class> datatype, final String methodName, final Set lookupMode,
- final Object... args) throws NoSuchMethodException {
- return findCompatibleMethod(datatype, methodName, lookupMode, TypeUtils.collectTypes(args));
- }
-
- /**
- * Same as getConstructor(), except for getting a {@link Method} of a classtype, using the name to indicate which method should be
- * located.
- *
- * @param datatype The class to get the constructor from.
- * @param methodName The name of the method to retrieve from the class.
- * @param lookupMode Flag indicating the search steps that need to be done.
- * @param signature The list of types as specified by the user.
- * @return The method if found, otherwise exception is thrown.
- * @exception NoSuchMethodException Thrown when the {@link Method} could not be found on the data type, even after performing optional
- * conversions.
- */
- @NotNull
- @SuppressWarnings("WeakerAccess")
- public static Set> findCompatibleMethod(final Class> datatype, final String methodName, final Set lookupMode,
- final Class>... signature) throws NoSuchMethodException {
- // first try to find the method in the method cache
- Set> iMethods = getMethodFromCache(datatype, methodName, signature);
- if (iMethods != null) {
- return iMethods;
- } else {
- iMethods = new HashSet<>();
- try {
- // try standard call
- iMethods.add(new InvokableObject<>(getMethod(datatype, methodName, signature), signature, signature));
- } catch (final NoSuchMethodException e) {
- for (final Class>[] compatibleSignature : TypeUtils.generateCompatibleTypeLists(lookupMode, signature)) {
- try {
- iMethods.add(new InvokableObject<>(getMethod(datatype, methodName, compatibleSignature), signature, compatibleSignature));
- } catch (final NoSuchMethodException x) {
- // do nothing
- }
- }
- }
- }
-
- if (!iMethods.isEmpty()) {
- return addMethodToCache(datatype, methodName, iMethods, signature);
- } else {
- throw new NoSuchMethodException();
- }
- }
-
- /**
- * Searches a specific class object for a {@link Method} using java reflect using a specific signature. This method will first search all
- * implemented interfaces for the method to avoid visibility problems.
- *
- * An example of such a problem is the Iterator as implemented by the ArrayList. The Iterator is implemented as a
- * private innerclass and as such not accessible by java reflect (even though the implemented methods are declared public), unlike the
- * interface's definition.
- *
- * @param datatype The class reference to locate the method on.
- * @param name The name of the method to find.
- * @param signature The signature the method should match.
- * @return The Method found on the data type that matched the specified signature.
- * @exception NoSuchMethodException Thrown when the {@link Method} could not be found on the interfaces implemented by the given data type.
- * @see java.lang.Class#getMethod(String, Class[])
- */
- @SuppressWarnings("WeakerAccess")
- @NotNull
- public static Method getMethod(final Class> datatype, final String name, final Class>... signature) throws NoSuchMethodException {
- for (final Class> iface : datatype.getInterfaces()) {
- try {
- return iface.getMethod(name, signature);
- } catch (final NoSuchMethodException e) {
- // do nothing
- }
- }
- try {
- return datatype.getMethod(name, signature);
- } catch (final NoSuchMethodException e) {
- return datatype.getDeclaredMethod(name, signature);
- }
- }
-
- /**
- * Tests if a list of classes is compatible with the signature of the given method, allowing for {@link LookupMode#SIMPLE} lookup mode.
- */
- @SuppressWarnings({"unused"})
- public static boolean isMethodCompatible(Method method, final Object... signature) {
- return isMethodCompatible(method, LookupMode.SIMPLE, signature);
- }
-
- /**
- * Tests if a list of classes is compatible with the signature of the given method, allowing for the given lookup modes.
- */
- @SuppressWarnings({"unused"})
- public static boolean isMethodCompatible(Method method, Set lookupMode, final Object... signature) {
- return isMethodCompatible(method, lookupMode, TypeUtils.collectTypes(signature));
- }
-
- /**
- * Tests if a list of arguments is compatible with the signature of the given method, allowing for {@link LookupMode#SIMPLE} lookup mode.
- */
- @SuppressWarnings({"unused"})
- public static boolean isMethodCompatible(Method method, final Class>... signature) {
- return isMethodCompatible(method, LookupMode.SIMPLE, signature);
- }
-
- /**
- * Tests if a list of arguments is compatible with the signature of the given method, allowing for the given lookup modes.
- */
- @SuppressWarnings({"unused", "WeakerAccess"})
- public static boolean isMethodCompatible(Method method, Set lookupMode, final Class>... signature) {
- final Class>[] targetSignature = method.getParameterTypes();
- if (signature.length != targetSignature.length) {
- return false;
- }
- return TypeUtils.isTypeListCompatible(signature, targetSignature, lookupMode);
- }
-
- /**
- * Delegates to {@link #zipParametersAndArguments(boolean, Method, Object...)} with strict type checking.
- */
- @SuppressWarnings({"unused"})
- @Nullable
- public static LinkedHashMap zipParametersAndArguments(Method method, Object... arguments) {
- return zipParametersAndArguments(true, method, arguments);
- }
-
- /**
- * Given a method and a list of arguments, return a map of parameters matching their arguments.
- *
- * @param strictTypeChecking Indicates whether the parameters types should be checked for compatibility with the
- * arguments provided. If true and the signature doesn't match, return {@code null}, or else
- * zip values as given using the lowest length.
- */
- @SuppressWarnings({"unused"})
- @Nullable
- public static LinkedHashMap zipParametersAndArguments(boolean strictTypeChecking, Method method, Object... arguments) {
- if (!strictTypeChecking || isMethodCompatible(method, arguments)) {
- final LinkedHashMap result = new LinkedHashMap<>();
- for (int i = 0; i < Math.min(method.getParameterTypes().length, arguments.length); i++) {
- result.put(new MethodParameter(i,
- method.getParameterTypes()[i],
- method.getGenericParameterTypes()[i],
- Arrays.asList(method.getParameterAnnotations()[i])), arguments[i]);
- }
- return result;
- }
- return null;
- }
-
- /**
- * Retrieves a {@link Method} from a cache.
- *
- * @param datatype The owning {@link Class} of the Method being searched for.
- * @param method The name of the method that is being searched for.
- * @param signature The parameter list of the method we need to match if a method was found by name.
- * @return The Method found on the specified owner with matching name and signature.
- * @see LookupCaches#METHOD_CACHE
- * @see MethodUtils#addMethodToCache(Class, String, Set, Class[])
- */
- @Nullable
- private static Set getInvokableObjectFromCache(final Class datatype, final String method, final Class>... signature) {
- final Map[], Set>> owner = METHOD_CACHE.get(datatype);
- // we know only methods with parameter list are stored in the cache
- if (signature.length > 0) {
- // get owner, its methods matching specified name and match their signatures
- if (owner != null && owner.containsKey(method)) {
- return owner.get(method).get(signature);
- }
- }
- // method not found or known not to be stored due to absent parameter list
- return null;
- }
-
- @Nullable
- private static Set> getMethodFromCache(final Class datatype, final String method, final Class>... signature) {
- return trustedNullableCast(getInvokableObjectFromCache(datatype, method, signature));
- }
-
- @Nullable
- private static Set> getConstructorFromCache(final Class datatype, final String method, final Class>... signature) {
- return trustedNullableCast(getInvokableObjectFromCache(datatype, method, signature));
- }
-
- /**
- * Adds a specific Method to the cache.
- *
- * @param datatype The Class that owns the Method.
- * @param method The Method's name by which methods can be found on the specified owner.
- * @param methodInvocationCandidates The Method reference that's actually being stored in the cache.
- * @param signature The parameter list of the Method being stored.
- * @see LookupCaches#METHOD_CACHE
- * @see MethodUtils#getMethodFromCache(Class, String, Class...)
- */
- private static , T2 extends AccessibleObject> Set addMethodToCache(final Class> datatype, final String method,
- final Set methodInvocationCandidates, final Class>... signature) {
- // only store methods with a parameter list
- if (signature.length > 0) {
- // get or create owner entry
- Map[], Set>> owner = METHOD_CACHE.get(datatype);
- owner = owner != null ? owner : new LinkedHashMap[], Set>>();
- // get or create list of methods with specified method name
- Map[], Set> methods = owner.get(method);
- methods = methods != null ? methods : new LinkedHashMap[], Set>();
- // add or overwrite method entry
- methods.put(signature, MiscUtil.>trustedCast(methodInvocationCandidates));
- // finally shelve all the stuff back
- methods.put(signature, MiscUtil.>trustedCast(methodInvocationCandidates));
- owner.put(method, methods);
- METHOD_CACHE.put(datatype, owner);
- }
- return methodInvocationCandidates;
- }
-
-
- /**
- * Delegates to {@link #findMatchingMethods(Class, Class, String, String...)}
- */
- @SuppressWarnings({ "unused", "WeakerAccess" })
- public static Set findMatchingMethods(final Class> datatype, @Nullable Class> boundaryMarker, String methodName, List paramTypeNames) {
- return findMatchingMethods(datatype, boundaryMarker, methodName, paramTypeNames.toArray(new String[0]));
- }
-
- /**
- * @return Methods found using {@link ClassUtils#collectMethods(Class, Class, EnumSet)}
- * and then filters based on the parameter type names.
- */
- @SuppressWarnings({ "unused", "WeakerAccess" })
- public static Set findMatchingMethods(final Class> datatype, @Nullable Class> boundaryMarker, String methodName, String... paramTypeNames) {
- Set matchingMethods = new HashSet<>();
- for (Method method : ClassUtils.collectMethods(datatype, boundaryMarker, MethodModifier.MATCH_ANY)) {
- Class>[] methodParameterTypes = method.getParameterTypes();
- if (method.getName().equals(methodName) &&
- methodParameterTypes.length == paramTypeNames.length &&
- typeNamesMatch(methodParameterTypes, paramTypeNames)) {
- matchingMethods.add(method);
- }
- }
- return matchingMethods;
- }
-
- private static boolean typeNamesMatch(Class>[] parameterTypes, String[] typeNamesToMatch) {
- for (int i = 0; i < parameterTypes.length; i++) {
- final Class> parameterType = parameterTypes[i];
- final String typeNameToMatch = typeNamesToMatch[i];
- if (parameterType.isArray()) {
- final String arrayTypeNameToMatch = typeNameToMatch.endsWith("...")
- ? typeNameToMatch.substring(0, typeNameToMatch.indexOf("..."))
- : typeNameToMatch;
- if (typeNamesDontMatch(parameterType.getComponentType(), arrayTypeNameToMatch)) {
- return false;
- }
- } else if (typeNamesDontMatch(parameterType, typeNameToMatch)) {
- return false;
- }
- }
- return true;
- }
-
- private static boolean typeNamesDontMatch(Class> parameterType, String typeNameToMatch) {
- return !parameterType.getName().equals(typeNameToMatch) && !parameterType.getSimpleName().equals(typeNameToMatch);
- }
-
- /**
- * @return True if the given method contains a parameter that is an array of an {@link Iterable}.
- */
- @SuppressWarnings("WeakerAccess")
- public static boolean methodHasCollectionParameter(final Method m) {
- for (Class> parameterType : m.getParameterTypes()) {
- if (parameterType.isArray() ||
- Iterable.class.isAssignableFrom(parameterType) ||
- Map.class.isAssignableFrom(parameterType)) {
- return true;
- }
- }
- return false;
- }
-
- public static Method onlyMethod(Set> methods) {
- if (methods.size() == 0) {
- return null;
- } else if (methods.size() == 1) {
- return methods.iterator().next().getMethod();
- } else {
- throw new AssertionError("Expected 1 or less methods, but found more than 1 methods: " + methods);
- }
- }
-
- @SuppressWarnings("unchecked")
- @Nullable
- public static Target firstParameterArgumentByAnnotation(Method method, Object[] arguments, Class annotationClass) {
- if (isMethodCompatible(method, arguments)) {
- for (int i = 0; i < method.getParameterTypes().length; i++) {
- if (containsAnnotation(method.getParameterAnnotations()[i], annotationClass)) {
- return (Target) arguments[i];
- }
- }
- }
- return null;
- }
-
- public static int firstParameterIndexByAnnotation(Method method, Class annotationClass) {
- for (int i = 0; i < method.getParameterTypes().length; i++) {
- if (containsAnnotation(method.getParameterAnnotations()[i], annotationClass)) {
- return i;
- }
- }
- return -1;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/bbottema/javareflection/PackageUtils.java b/src/main/java/org/bbottema/javareflection/PackageUtils.java
deleted file mode 100644
index a568a57..0000000
--- a/src/main/java/org/bbottema/javareflection/PackageUtils.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.bbottema.javareflection;
-
-import lombok.experimental.UtilityClass;
-import org.jetbrains.annotations.Nullable;
-
-@SuppressWarnings("WeakerAccess")
-@UtilityClass
-public final class PackageUtils {
-
- @Nullable
- static Class> scanPackagesForClass(String className, @Nullable String inPackage, @Nullable ClassLoader classLoader) {
- // cycle through all sub-packages and try allocating class dynamically
- for (Package currentPackage : Package.getPackages()) {
- final String packageName = currentPackage.getName();
- if (inPackage == null || packageName.startsWith(inPackage)) {
- final Class> _class = ClassUtils.locateClass(packageName + "." + className, classLoader);
- if (_class != null) {
- return _class;
- }
- }
- }
- return null;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/bbottema/javareflection/ReflectionUtils.java b/src/main/java/org/bbottema/javareflection/ReflectionUtils.java
deleted file mode 100644
index 3e66f1f..0000000
--- a/src/main/java/org/bbottema/javareflection/ReflectionUtils.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.bbottema.javareflection;
-
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * This util is able to find Generic types as Class instances. This is useful for determining class types in runtime, which is (mostly) used by
- * converters.
- */
-public class ReflectionUtils {
-
- @SuppressWarnings("FieldCanBeLocal")
- private static final String INVALID_GENERIC_TYPE_DEFINITION = "Unable to determine generic type, probably due to type erasure. Make sure the type is part of a class signature (it can not be a field or variable, or a nested generic type such as List)";
-
- /**
- * Inspects a inheritance chain of classes until the classOfInterest is found and then will look for the Generic type declared for the given (zero-based) index.
- */
- @SuppressWarnings("unchecked")
- public static Class findParameterType(Class> instanceClass, Class> classOfInterest, int parameterIndex) {
- Map typeMap = new HashMap<>();
- while (classOfInterest != instanceClass.getSuperclass()) {
- extractTypeArguments(typeMap, instanceClass);
- instanceClass = instanceClass.getSuperclass();
- if (instanceClass == null)
- throw new IllegalArgumentException();
- }
-
- ParameterizedType parameterizedType = (ParameterizedType) instanceClass.getGenericSuperclass();
- Type actualType = parameterizedType.getActualTypeArguments()[parameterIndex];
- if (typeMap.containsKey(actualType)) {
- actualType = typeMap.get(actualType);
- }
- if (actualType instanceof Class) {
- return (Class) actualType;
- } else {
- try {
- return (Class) ((ParameterizedType) actualType).getRawType();
- } catch (ClassCastException e) {
- throw new IllegalStateException(INVALID_GENERIC_TYPE_DEFINITION, e);
- }
- }
- }
-
- private static void extractTypeArguments(Map typeMap, Class> clazz) {
- Type genericSuperclass = clazz.getGenericSuperclass();
- if (!(genericSuperclass instanceof ParameterizedType)) {
- return;
- }
-
- ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
- Type[] typeParameter = ((Class>) parameterizedType.getRawType()).getTypeParameters();
- Type[] actualTypeArgument = parameterizedType.getActualTypeArguments();
- for (int i = 0; i < typeParameter.length; i++) {
- if (typeMap.containsKey(actualTypeArgument[i])) {
- actualTypeArgument[i] = typeMap.get(actualTypeArgument[i]);
- }
- typeMap.put(typeParameter[i], actualTypeArgument[i]);
- }
- }
-}
diff --git a/src/main/java/org/bbottema/javareflection/TypeUtils.java b/src/main/java/org/bbottema/javareflection/TypeUtils.java
deleted file mode 100644
index 09eecf1..0000000
--- a/src/main/java/org/bbottema/javareflection/TypeUtils.java
+++ /dev/null
@@ -1,339 +0,0 @@
-package org.bbottema.javareflection;
-
-import lombok.experimental.UtilityClass;
-import org.bbottema.javareflection.model.LookupMode;
-import org.bbottema.javareflection.util.ArrayKey;
-import org.bbottema.javareflection.valueconverter.ValueConversionHelper;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.lang.annotation.Annotation;
-import java.util.*;
-
-import static org.bbottema.javareflection.LookupCaches.*;
-
-/**
- * Utility functions that deal with type information, conversions and autoboxing.
- *
- * Particularly of interest is {@link #generateCompatibleTypeLists(Set, Class[])},
- * which generates a collection of type lists which can be derived from the input type
- * list. This is usful for method matching, since Java reflection doesn't take into account
- * autoboxing, casting or auto widening, let alone type conversions.
- *
- * Types that are candidates for Autoboxing:
- *
- *
booleanjava.lang.Boolean
- *
charjava.lang.Character
- *
bytejava.lang.Byte
- *
shortjava.lang.Short
- *
intjava.lang.Integer
- *
longjava.lang.Long
- *
floatjava.lang.Float
- *
doublejava.lang.Double
- *
- *
- * For types that are candidates for common conversion, please see {@link ValueConversionHelper}.
- */
-@UtilityClass
-public final class TypeUtils {
-
- /**
- * A list with Number types in ascending order to wideness (or size) of each type (ie. double is wider than integer).
- */
- private static final Map, Integer> numSizes;
-
- static {
- numSizes = new LinkedHashMap<>();
- int size = 0;
- numSizes.put(Byte.class, ++size);
- numSizes.put(Short.class, ++size);
- numSizes.put(Integer.class, ++size);
- numSizes.put(Long.class, ++size);
- numSizes.put(Float.class, ++size);
- numSizes.put(Double.class, ++size);
- }
-
- /**
- * Creates a new array of class objects harvested from an array of objects.
- *
- * NOTE: this method will never return primitive classes (such as double.class, as you can't put primitive values into an array of Objects (they
- * will be autoboxes by the JVM).
- *
- * @param objects The array of objects to harvest classtypes from.
- * @return The array with the harvested classtypes.
- */
- @NotNull
- @SuppressWarnings("WeakerAccess")
- public static Class>[] collectTypes(final Object[] objects) {
- // collect classtypes of the arguments
- final Class>[] types = new Class>[objects.length];
- for (int i = 0; i < objects.length; i++) {
- final Object o = objects[i];
- types[i] = o != null ? o.getClass() : null;
- }
- return types;
- }
-
- @SuppressWarnings({"unused", "WeakerAccess"})
- public static boolean isTypeListCompatible(Class>[] inputTypeList, Class>[] targetTypeList, Set lookupMode) {
- List[]> derivableTypeLists = generateCompatibleTypeLists(lookupMode, inputTypeList);
-
- for (Class>[] derivableTypeList : derivableTypeLists) {
- boolean currentTypeListCompatible = true;
- for (int i = 0; i < derivableTypeList.length && currentTypeListCompatible; i++) {
- if (derivableTypeList[i] != null && !derivableTypeList[i].equals(targetTypeList[i])) {
- currentTypeListCompatible = false;
- }
- }
- if (currentTypeListCompatible) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Initializes the list with type-arrays and starts generating beginning from index 0. This method is used for (un)wrapping.
- *
- * @param lookupMode Flag indicating the search steps that need to be done.
- * @param inputTypelist The list with original user specified types.
- * @return The list with converted type-arrays.
- */
- @NotNull
- @SuppressWarnings({"unused", "WeakerAccess"})
- public static List[]> generateCompatibleTypeLists(final Set lookupMode, final Class>... inputTypelist) {
- final ArrayKey arrayKey = new ArrayKey(inputTypelist);
- final List[]> cachedResult = getCachedCompatibleSignatures(lookupMode, arrayKey);
- return cachedResult != null
- ? cachedResult
- : addCompatiblesignaturesToCache(lookupMode, arrayKey,
- generateCompatibleTypeLists(0, lookupMode, new ArrayList[]>(), inputTypelist));
- }
-
- /**
- * Recursively generates a complete list of all possible (un)wraps (autoboxing), supertypes, implemented interfaces, type conversions and any
- * combination thereof with the specified typeLists's elements (the individual parameter types).
- *
- * The combination typeLists are generated in the following order:
- *
- *
no conversion; highest priority as it comes closest to user's requirement/specification
- *
autoboxing; the autoboxed counterversion comes closest to the original datatype
- *
interface; where methods can't be found using original type, interface placeholders are attempted
- *
supertype; where methods can't be found using implemented interfaces, supertype placeholders are attempted
- *
conversions; if all else fails, try to convert the datatype for common types (ie. int to String)
- *
- * @param index The current index to start mutating from.
- * @param lookupMode Flag indicating the search steps that need to be done.
- * @param inputTypelist The list with current types, to mutate further upon.
- */
- private static List[]> generateCompatibleTypeLists(final int index, final Set lookupMode, final List[]> compatibleTypeLists, final Class>... inputTypelist) {
- // if new type array is completed
- if (index == inputTypelist.length) {
- compatibleTypeLists.add(inputTypelist);
- } else {
- // generate new array of types
- final Class> original = inputTypelist[index];
-
- // 1. don't generate compatible list; just try the normal type first
- // remember, in combinations types should be allowed to be converted)
- generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, inputTypelist.clone());
-
- if (original != null) {
- // 2. generate type in which the original can be (un)wrapped
- if (lookupMode.contains(LookupMode.AUTOBOX) && !lookupMode.contains(LookupMode.SMART_CONVERT)) {
- final Class> autoboxed = autobox(original);
- if (autoboxed != null) {
- final Class>[] newTypeList = replaceInArray(inputTypelist.clone(), index, autoboxed);
- generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
- }
- }
-
- // autocast to supertype or interface?
- if (lookupMode.contains(LookupMode.CAST_TO_INTERFACE)) {
- // 3. generate implemented interfaces the original value could be converted (cast) into
- for (final Class> iface : original.getInterfaces()) {
- final Class>[] newTypeList = replaceInArray(inputTypelist.clone(), index, iface);
- generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
- }
- }
-
- if (lookupMode.contains(LookupMode.CAST_TO_SUPER)) {
- // 4. generate supertypes the original value could be converted (cast) into
- Class> supertype = original;
- while ((supertype = supertype.getSuperclass()) != null) {
- final Class>[] newTypeList = replaceInArray(inputTypelist.clone(), index, supertype);
- generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
- }
- }
-
- // 5. generate types the original value could be converted into
- if (lookupMode.contains(LookupMode.COMMON_CONVERT) && !lookupMode.contains(LookupMode.SMART_CONVERT)) {
- for (final Class> convert : collectRegisteredCompatibleTargetTypes(original)) {
- final Class>[] newTypeList = replaceInArray(inputTypelist.clone(), index, convert);
- generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
- }
- }
-
- // 6. generate types the original value could be converted into with intermediary conversions
- if (lookupMode.contains(LookupMode.SMART_CONVERT)) {
- for (final Class> convert : collectCompatibleTargetTypes(original)) {
- final Class>[] newTypeList = replaceInArray(inputTypelist.clone(), index, convert);
- generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
- }
- }
- }
- }
-
- return compatibleTypeLists;
- }
-
- @NotNull
- private static Set> collectRegisteredCompatibleTargetTypes(Class> fromType) {
- if (!CACHED_REGISTERED_COMPATIBLE_TARGET_TYPES.containsKey(fromType)) {
- CACHED_REGISTERED_COMPATIBLE_TARGET_TYPES.put(fromType, ValueConversionHelper.collectRegisteredCompatibleTargetTypes(fromType));
- }
- return CACHED_REGISTERED_COMPATIBLE_TARGET_TYPES.get(fromType);
- }
-
- @NotNull
- private static Set> collectCompatibleTargetTypes(Class> fromType) {
- if (!CACHED_COMPATIBLE_TARGET_TYPES.containsKey(fromType)) {
- CACHED_COMPATIBLE_TARGET_TYPES.put(fromType, ValueConversionHelper.collectCompatibleTargetTypes(fromType));
- }
- return CACHED_COMPATIBLE_TARGET_TYPES.get(fromType);
- }
-
- /**
- * Emulates Java's Autoboxing feature; tries to convert a type to its (un)wrapped counter version.
- *
- * @param c The datatype to convert (autobox).
- * @return The converted version of the specified type, or null.
- */
- @Nullable
- @SuppressWarnings("WeakerAccess")
- public static Class> autobox(final Class> c) {
- // integer
- if (c == Integer.class) {
- return int.class;
- } else if (c == int.class) {
- return Integer.class;
- } else if (c == Boolean.class) {
- return boolean.class;
- } else if (c == boolean.class) {
- return Boolean.class;
- } else if (c == Character.class) {
- return char.class;
- } else if (c == char.class) {
- return Character.class;
- } else if (c == Byte.class) {
- return byte.class;
- } else if (c == byte.class) {
- return Byte.class;
- } else if (c == Short.class) {
- return short.class;
- } else if (c == short.class) {
- return Short.class;
- } else if (c == Long.class) {
- return long.class;
- } else if (c == long.class) {
- return Long.class;
- } else if (c == Float.class) {
- return float.class;
- } else if (c == float.class) {
- return Float.class;
- } else if (c == Double.class) {
- return double.class;
- } else if (c == double.class) {
- return Double.class;
- } else {
- return null;
- }
- }
- /**
- * Returns the smallest class that can hold all of the specified numbers.
- *
- * @param numbers The list with numbers that all should fit in the Number container.
- * @return The Number container that is just large enough for all specified numbers.
- */
- @NotNull
- @SuppressWarnings("WeakerAccess")
- public static Class> widestNumberClass(final Number... numbers) {
- Integer widest = 0;
- Class> widestNumberType = Byte.class;
- for (final Number number : numbers) {
- final Integer size = numSizes.get(number.getClass());
- if (size > widest) {
- widestNumberType = number.getClass();
- widest = size;
- }
- }
- return widestNumberType;
- }
-
- /**
- * Validates whether a string represents a valid package.
- *
- * @param name The string representing a list of packages.
- * @return A boolean indicating whether name represents a valid package.
- */
- @SuppressWarnings("WeakerAccess")
- public static boolean isPackage(final String name) {
- return name.equals("java") || Package.getPackage(name) != null;
- }
-
- /**
- * @return Whether a given list of Annotation contains a certain annotation type.
- * @see #findAnnotation(Collection, Class)
- */
- @SuppressWarnings("WeakerAccess")
- public static boolean containsAnnotation(List myListOfAnnotations, Class extends Annotation> annotationClass) {
- return findAnnotation(myListOfAnnotations, annotationClass) != null;
- }
-
- /**
- * @return Whether a given list of Annotation contains a certain annotation type.
- * @see #findAnnotation(Annotation[], Class)
- */
- public static boolean containsAnnotation(Annotation[] myListOfAnnotations, Class extends Annotation> annotationClass) {
- return findAnnotation(myListOfAnnotations, annotationClass) != null;
- }
-
- /**
- * @return Whether a given list of Annotation contains a certain annotation type.
- * @see #findAnnotation(Annotation[], Class)
- */
- @SuppressWarnings({"WeakerAccess"})
- @Nullable
- public static T findAnnotation(Collection myListOfAnnotations, Class annotationClass) {
- return findAnnotation(myListOfAnnotations.toArray(new Annotation[0]), annotationClass);
- }
-
- /**
- * @return Whether a given list of Annotation contains a certain annotation type.
- */
- @SuppressWarnings({"WeakerAccess", "unchecked"})
- @Nullable
- public static T findAnnotation(Annotation[] myListOfAnnotations, Class annotationClass) {
- for (Annotation annotation : myListOfAnnotations) {
- if (annotation.annotationType() == annotationClass) {
- return (T) annotation;
- }
- }
- return null;
- }
-
- /**
- * Shortcut helper method that replaces an item in an array and returns the array itself.
- *
- * @param The type of object that goes into the array.
- * @param array The array that needs an item replaced.
- * @param index The index at which the new value should be inserted.
- * @param value The value to insert at the specified index in the specified array.
- * @return The specified array with the item replaced at specified index.
- */
- @NotNull
- static T[] replaceInArray(final T[] array, final int index, final T value) {
- array[index] = value;
- return array;
- }
-}
diff --git a/src/main/java/org/bbottema/javareflection/model/FieldWrapper.java b/src/main/java/org/bbottema/javareflection/model/FieldWrapper.java
deleted file mode 100644
index 02ac3f6..0000000
--- a/src/main/java/org/bbottema/javareflection/model/FieldWrapper.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.bbottema.javareflection.model;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import lombok.Value;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-/**
- * A wrapper class that keeps a property ({@link Field}) and its setter/getter method(s) in one place.
- */
-@Value
-@SuppressFBWarnings(justification = "Generated code")
-public class FieldWrapper {
-
- @NotNull
- private final Field field;
- @Nullable
- private final Method getter;
- @Nullable
- private final Method setter;
-}
\ No newline at end of file
diff --git a/src/main/java/org/bbottema/javareflection/model/InvokableObject.java b/src/main/java/org/bbottema/javareflection/model/InvokableObject.java
deleted file mode 100644
index 958f9a6..0000000
--- a/src/main/java/org/bbottema/javareflection/model/InvokableObject.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.bbottema.javareflection.model;
-
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import lombok.Data;
-import lombok.NonNull;
-
-import java.lang.reflect.AccessibleObject;
-
-@Data
-@SuppressFBWarnings(justification = "Generated code")
-public class InvokableObject {
- @NonNull T method;
- @NonNull Class>[] inputSignature;
- @NonNull Class>[] compatibleSignature;
-}
\ No newline at end of file
diff --git a/src/main/java/org/bbottema/javareflection/model/LookupMode.java b/src/main/java/org/bbottema/javareflection/model/LookupMode.java
deleted file mode 100644
index 1de1203..0000000
--- a/src/main/java/org/bbottema/javareflection/model/LookupMode.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.bbottema.javareflection.model;
-
-import org.bbottema.javareflection.valueconverter.ValueConversionHelper;
-
-import java.util.Set;
-
-import static java.util.Collections.unmodifiableSet;
-import static java.util.EnumSet.allOf;
-import static java.util.EnumSet.of;
-
-/**
- * Defines lookup modes for matching Java methods and constructors. Each time a lookup failed on signature type, a less strict lookup
- * is performed, in the following order (signature means: the list of parameters defined for a method or constructor):
- *
- *
exact matching: the given type should exactly match the found types during lookup. This lookup cycle is always performed
- * first.
- *
autobox matching: the given type should match its boxed/unboxed version.
- *
polymorphic interface matching: the given type should match one of the implemented interfaces
- *
polymorphic superclass matching: the given type should match one of the super classes (for each superclass, the cycle is
- * repeated, so exact and interface matching come first again before the next superclass up in the chain)
- *
common conversion matching: if all other lookups fail, one last resort is to try to convert the given type, if a common
- * type, to any other common type and then try to find a matching method or constructor. See {@link ValueConversionHelper} for more on the possibilities.
- *
- *
- */
-public enum LookupMode {
- /**
- * Indicates that looking for methods includes trying to find compatible signatures by autoboxing the specified arguments.
- */
- AUTOBOX,
- /**
- * Indicates that looking for methods includes trying to find compatible signatures by casting the specified arguments to a super type.
- */
- CAST_TO_SUPER,
- /**
- * Indicates that looking for methods includes trying to find compatible signatures by casting the specified arguments to an implemented
- * interface.
- */
- CAST_TO_INTERFACE,
- /**
- * Indicates that looking for methods includes trying to find compatible signatures by automatically converting the specified arguments.
- */
- COMMON_CONVERT,
- /**
- * Like {@link #COMMON_CONVERT}, but now takes the registered converters and continues finding a conversion path based on the previous outcomes.
- *
- * Examples:
- *
- *
Joda date object -> String -> Java8 date object. This would require only the toJava8 date object converter to work
- *
Calendar -> String -> char. Calendar is compatible with String and String with char, but conversion will fail of course.
- *
Boolean -> Character -> long. This simply works out of the box, resulting in 0 or 1.
- *
- */
- SMART_CONVERT;
-
- /**
- * Defines a simple method lookup configuration that goes as far as casting and autoboxing, but no actual conversions are done to the values.
- */
- public static final Set SIMPLE = of(AUTOBOX, CAST_TO_SUPER, CAST_TO_INTERFACE);
-
- /**
- * Defines a complete method lookup configuration that combines all possible lookup modes.
- */
- public static final Set FULL = unmodifiableSet(allOf(LookupMode.class));
-}
diff --git a/src/main/java/org/bbottema/javareflection/model/MethodModifier.java b/src/main/java/org/bbottema/javareflection/model/MethodModifier.java
deleted file mode 100644
index 6a9f3fb..0000000
--- a/src/main/java/org/bbottema/javareflection/model/MethodModifier.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.bbottema.javareflection.model;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.EnumSet;
-
-import static java.util.EnumSet.allOf;
-
-@SuppressWarnings("unused")
-public enum MethodModifier {
- PUBLIC(Modifier.PUBLIC),
- PROTECTED(Modifier.PROTECTED),
- PRIVATE(Modifier.PRIVATE),
- ABSTRACT(Modifier.ABSTRACT),
- DEFAULT(-1),
- STATIC(Modifier.STATIC),
- FINAL(Modifier.FINAL),
- SYNCHRONIZED(Modifier.SYNCHRONIZED),
- NATIVE(Modifier.NATIVE),
- STRICT(Modifier.STRICT);
-
- public static final EnumSet MATCH_ANY = allOf(MethodModifier.class);
-
- private final int modifierFlag;
-
- MethodModifier(int modifierFlag) {
- this.modifierFlag = modifierFlag;
- }
-
- public static boolean meetsModifierRequirements(Method method, EnumSet modifiers) {
- final int m = method.getModifiers();
-
- for (MethodModifier methodModifier : modifiers) {
- if (methodModifier != MethodModifier.DEFAULT) {
- if ((m & methodModifier.modifierFlag) != 0) {
- return true;
- }
- } else {
- if (!Modifier.isPrivate(m) && !Modifier.isProtected(m) && !Modifier.isPublic(m)) {
- return true;
- }
- }
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/bbottema/javareflection/model/MethodParameter.java b/src/main/java/org/bbottema/javareflection/model/MethodParameter.java
deleted file mode 100644
index 98b701f..0000000
--- a/src/main/java/org/bbottema/javareflection/model/MethodParameter.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.bbottema.javareflection.model;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import lombok.Value;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.Collection;
-
-@Value
-@SuppressFBWarnings(justification = "Generated code")
-public class MethodParameter {
- final int index;
- final Class> type;
- final Type genericType;
- final Collection annotations;
-}
\ No newline at end of file
diff --git a/src/main/java/org/bbottema/javareflection/util/ArrayKey.java b/src/main/java/org/bbottema/javareflection/util/ArrayKey.java
deleted file mode 100644
index 4a2d860..0000000
--- a/src/main/java/org/bbottema/javareflection/util/ArrayKey.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.bbottema.javareflection.util;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-import java.util.Arrays;
-
-import static org.bbottema.javareflection.util.MiscUtil.requireNonNullOfType;
-
-/**
- * Needed to make sure hashcode and equals are implemented properly for arrays as key in a map.
- */
-public class ArrayKey {
-
- private final int hashCode;
- private final Class>[] array;
-
- public ArrayKey(Class>[] array) {
- this.array = array.clone();
- this.hashCode = Arrays.hashCode(this.array);
- }
-
- @SuppressFBWarnings(value = "EQ_UNUSUAL", justification = "Equals is specifically implemented for performance reasons")
- @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
- @Override
- public boolean equals(Object o) {
- return o != null && Arrays.equals(array, requireNonNullOfType(o, ArrayKey.class).array);
- }
-
- @Override
- public int hashCode() {
- return hashCode;
- }
-
- @Override
- public String toString() {
- return Arrays.toString(array);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/bbottema/javareflection/util/ExternalClassLoader.java b/src/main/java/org/bbottema/javareflection/util/ExternalClassLoader.java
deleted file mode 100644
index c570ee5..0000000
--- a/src/main/java/org/bbottema/javareflection/util/ExternalClassLoader.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package org.bbottema.javareflection.util;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.DataInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A toolkit that can read and compile .java sourcefiles on the fly in runtime. This class loader caches loaded classes for
- * repeated requests. Also, if a .class file already exists for a specific .java sourcefile, the classloader will compare dates and see if
- * the .java needs recompiling.
- *
- * A basepath can be specified for the classloader to look in for sourcefiles.
- */
-public final class ExternalClassLoader extends ClassLoader {
- /**
- * base path used to locate [packaged] classes in
- */
- @Nullable
- private String basepath;
-
- /**
- * List of classes. These are non-instances of a class, of which instances can be spawn.
- */
- @NotNull
- private final Map> classes = new HashMap<>();
-
- /**
- * The exception that was thrown when the class was actually found but some other error occurred.
- */
- @Nullable
- @SuppressWarnings("FieldCanBeLocal")
- private CompileException exception;
-
- /**
- * Constructor which initializes all properties.
- */
- public ExternalClassLoader() {
- super(ExternalClassLoader.class.getClassLoader());
- }
-
- /**
- * Loads a class from the classes cache if available. Delegates to {@link #findClass(String)} otherwise.
- *
- * @see ClassLoader#loadClass(String)
- */
- @Override
- @Nullable
- public final Class> loadClass(final String className)
- throws ClassNotFoundException {
- final Class> c = classes.get(className);
- return (c != null) ? c : findClass(className);
- }
-
- /**
- * Loads a classfile from file in the following order:
- *
- *
looks for the java source and if available, checks whether it needs to be compiled
- *
if no .java or .class file found, try to find it in the VM
- *
- * If the class ultimately wasn't found a ClassNotFoundException is being thrown. If class was found, but an error
- * occurred, store exception for later review and return null. This is done so because the overridden method can't throw an
- * exception other than ClassNotFoundException.
- *
- * @param className The path and name to the classfile.
- * @return The requested class reference.
- * @throws ClassNotFoundException Thrown by {@link #findSystemClass(String)}.
- */
- @SuppressWarnings("WeakerAccess")
- @Override
- @Nullable
- public final Class> findClass(final String className)
- throws ClassNotFoundException {
- exception = null;
- try {
- // try to load, cache and return the class from compiled .class file
- checkForFile(basepath, className);
-
- // if a classfile is available then load it
- final Class> c = classes.get(className);
- if (c != null) {
- return c;
- } else {
- throw new ClassNotFoundException();
- }
- } catch (final ClassNotFoundException e) {
- // - see if class can be found in the VM
- // - this check must come last, else you won't detect whether a classfile has been recompiled
- final Class> c = findSystemClass(className);
- classes.put(className, c);
- return c;
- } catch (final IOException e) {
- exception = new CompileException(e.getMessage(), e);
- return null;
- } catch (final CompileException e) {
- exception = e;
- return null;
- }
- }
-
- /**
- * Reads and compiles the sourcefile from filesystem and creates the class inside the VM.
- *
- * @param className The path and name to the .java sourcefile.
- */
- private void checkForFile(final String classPath, final String className)
- throws IOException {
- // figure paths...
- final String resource = className.replace("..", "||").replace('.', File.separatorChar).replace("||", "..");
- final File javaSource = new File(classPath + File.separatorChar + resource + ".java");
- final File javaClass = new File(classPath + File.separatorChar + resource + ".class");
-
- final String absoluteClassPath = javaClass.getAbsolutePath();
-
- // see if there is a javafile and classfile
- if (javaSource.exists()) {
- // if classfile available, delete if outdated
- if (javaClass.exists()) {
- // determine if the java sourcefile has been modified since last compile
- // else check if the .class file has already been loaded
- if (javaSource.lastModified() > javaClass.lastModified()) {
- if (!javaClass.delete()) {
- throw new CompileException("runtime compiler: unable to removed outdated .class file");
- }
- classes.remove(className);
- } else if (classes.get(className) == null) {
- classes.put(className, loadClass(absoluteClassPath, className));
- }
- }
-
- // if no classfile available or became outdated
- if (!javaClass.exists()) {
- final int status = 0;// Main.compile(args);
-
- // load compiled classfile and cache it or return error that occured during compiling
- switch (status) {
- case 0:
- classes.put(className, loadClass(absoluteClassPath, className));
- break;
- case 1:
- throw new CompileException("runtime compiler: ERROR");
- case 2:
- throw new CompileException("runtime compiler: CMDERR");
- case 3:
- throw new CompileException("runtime compiler: SYSERR");
- case 4:
- throw new CompileException("runtime compiler: ABNORMAL");
- default:
- throw new CompileException("Compile status: Unknown exit status");
- }
- }
- }
- }
-
- /**
- * Reads the classfile from filesystem.
- *
- * @param classPath The path and name to the classfile.
- * @param className The name of the class to use as key for the Class reference value.
- */
- private Class> loadClass(final String classPath, final String className)
- throws IOException {
- // get data from file
- final File f = new File(classPath);
- final int size = (int) f.length();
- final byte[] buff = new byte[size];
- final DataInputStream dis = new DataInputStream(new FileInputStream(f));
- dis.readFully(buff);
- dis.close();
- // convert data into class
- return defineClass(className, buff, 0, buff.length, null);
- }
-
- /**
- * Parameterized exception used when Java's runtime compiler fails to compile a Java source file.
- */
- public static class CompileException extends RuntimeException {
- private static final long serialVersionUID = -7210219718456902667L;
-
- /**
- * @param reason The description of the cause of the exception.
- */
- CompileException(final String reason) {
- super(reason);
- }
-
- /**
- * Used to create an exception with a copies stacktrace (using {@link #setStackTrace(StackTraceElement[])}).
- *
- * @param reason The description of the cause of the exception.
- * @param cause A thrown exception that is the cause.
- */
- CompileException(final String reason, final Throwable cause) {
- super(reason + "\n " + cause.toString());
- setStackTrace(cause.getStackTrace());
- }
- }
-
- /**
- * Sets the base path this classloader will look for classes in.
- *
- * @param basepath A folder path to look for classes.
- */
- public void setBasepath(@Nullable final String basepath) {
- this.basepath = basepath;
- }
-
- @Nullable
- public String getBasepath() {
- return basepath;
- }
-
- @Nullable
- public CompileException getException() {
- return exception;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/bbottema/javareflection/util/Function.java b/src/main/java/org/bbottema/javareflection/util/Function.java
deleted file mode 100644
index e7a9ac2..0000000
--- a/src/main/java/org/bbottema/javareflection/util/Function.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.bbottema.javareflection.util;
-
-import static org.bbottema.javareflection.util.MiscUtil.trustedCast;
-
-public interface Function {
- T apply(F value);
-
- class Functions {
-
- private static final Function, ?> IDENTITY_FUNCTION = new Function