Understanding Apache Maven – Part 1 – The basics

Uncategorized

Published: 2020-05 (May 2020)
Verified with: Apache Maven 3.6.3

Link to an index, to find other blogs in this series.

This blog (a part of the series) is an introduction to Apache Maven basics.

Apache Maven (commonly referred to as “maven” ) is a Build Management tool. Maven is primarily used to build Java projects. Other language projects can also be built using maven. Apache Maven is written in Java, for most part. It is an open source project.

Maven follows a convention-over-configuration philosophy. More on this follows.

Why is Maven a Build Management tool?

Maven aims at achieving the following for a project:

  • build tooling
  • version management
  • re-usability
  • maintainability
  • comprehensibility
  • inheritance

In addition, maven provides capabilities for a project to :

  • produce different build targets and results builds via profiles
  • test code
  • generate documentation
  • furnish metrics and reports
  • deploy built artifacts

What is Convention-Over-Configuration?

Convention-over-configuration is a software paradigm. The main intent of such a paradigm is to reduce the number of superfluous decisions required by a developer to build her/his project. The paradigm aims to meet and satisfy the “principle of least astonishment“.

Apache Maven – convention over configuration

Apache Maven provides sensible defaults for a project’s build management. A developer can then choose to override any preset defaults.

An example of such is clear in the conventional directory structure of a maven project.

project
|
|____src
|   |
|   |____main
|   |   |
|   |   |____java
|   |   |
|   |   |____resources
|   |
|   |____test
|       |
|       |____java
|       |
|       |____resources
| 
|____pom.xml

Printed using: alias tree="find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'"

In this directory structure, the source code is, by convention located under the project root directory in a src directory. Under the src directory there exists a main directory that is, by convention expected to contain production code, that is, code that is expected to be a part of the final executable. Parallel to the main directory, there is a test directory, where test code is expected, by convention. Java code, once again, by convention (I think by now the point is made, will stop referring to it) exists in a java directory either in the production or in the test location. Similarly resources needed for production or test outputs, reside respectively in the resources directory.

This is just one example. Maven uses the convention-over-configuration philosophy in many other areas.

What are some Maven capabilities?

A few features that maven offers (this is not a comprehensive list):

  • Validate the project structure
  • Auto generate any code/resources needed by the project
  • Generate any documentation
  • Compile source code, display errors / warnings
  • Test the project based on existing tests
  • Package compiled code into artifacts (examples include .jar, .war, .ear, .zip archives and many more)
  • Package source code into downloadable archives / artifacts
  • Install packaged artifacts on to a server for deployment or into a repository for distribution
  • Generate site reports and test evidence
  • Report a build as success or failure
  • . . .

How does Maven work?

Maven uses a Project Object Model (POM) to manage a project. Maven commands execute parts of its Project Object Model. A Project Object Model is usually described as an XML document. A POM description is NOT limited to XML. Other formats can be used to describe the Project Object Model, however, XML was the first format used.

A picture to illustrate a typical maven execution:

A pictorial overview of how maven interacts with a project's Project Object Model. Includes assembling, download of dependencies and plugins, execution of build lifecycles and an upload of build artifacts to either a local repository or to a maven repository on a network
Maven – A pictorial overview

The next blog in this series will dig into details of a Project Object Model (POM). Have fun !

             IndexPart 2
The Project Object Model (POM) and Effective POMs

Understanding Apache Maven – The Series

Uncategorized

This is a series of blogs about Apache Maven – a build management tool. This series is intended to be an introductory set of blogs to introduce, familiarize or brush up on maven.

The blogs in this series:

Part 1 – Apache Maven basics
Bare Link: https://cguntur.me/2020/05/23/understanding-apache-maven-part-1/

Part 2 – The Project Object Model (POM) and Effective POMs
Bare Link: https://cguntur.me/2020/05/24/understanding-apache-maven-part-2/

Part 3 – Dependency coordinates and POM hierarchies
Bare Link: https://cguntur.me/2020/05/26/understanding-apache-maven-part-3/

Part 4 – Maven Lifecycles, Phases, Plugins and Goals
Bare Link: https://cguntur.me/2020/05/29/understanding-apache-maven-part-4/

Using JUnit5 – The series

Uncategorized

This is a series of blogs about JUnit 5 – a unit testing framework. This series is intended to be an introductory set of blogs to introduce, familiarize or brush up on JUnit 5.

The blogs in this series:

Part 1 – An Introduction
Bare Link: https://cguntur.me/2019/07/07/using-junit5-part-1/

Part 2 – Testing Basics
Bare Link: https://cguntur.me/2019/07/13/using-junit5-part-2/

Part 3 – Display Names
Bare Link: https://cguntur.me/2019/07/20/using-junit5-part-3/

Part 4 – Filtering Tests
Bare Link: https://cguntur.me/2019/07/27/using-junit5-part-4/

Java Method Handles – The NextGen Reflection

Uncategorized

Blog post date: 2018-06-10
Relevant Java Versions: Java 7+ (Method Handles were introduced in Java 7)

DukeReflection

Reflection was introduced in Java 1.1 (circa February 1997). Originally introduced as a tool for introspection, it quickly morphed into weapon to examine, introspect as well as alter both behavior and structure of a Java object, bypassing its member accessibility and instantiation rules. This feels very dangerous, and rightfully so, unless the application being built is a framework or a tool that is not fully aware of its operands and needs to dynamically bind such objects and work with/on them intimately.

JSR 292 (https://www.jcp.org/en/jsr/detail?id=292) a.k.a Multi-Language Virtual Machine (MLVM) and code-named: Da Vinci Machine Project, set out ease the implementations of dynamic language implementation and improve their performance, on the JVM. Core features that came to fruition thanks to the JSR:

  1. addition of a new invokedynamic instruction at the JVM level (helped dynamic type checking, the lambda support and performance improvements in other JVM languages, such as JRuby).
  2. ability to change classes and methods at runtime, dynamically (the focus of this blog).

The changes allowed for a lightweight reference to a method. A caller could thus, invoke a method through a method handle without knowing the method’s name, enclosing class, or exact signature, yet the call would run at nearly the speed of a statically linked Java call. These references are called MethodHandles.

API link: https://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandle.html

Intent

This blog post shows how Method Handles, as a more modern alternate to traditional reflection, can provide similar functionality to what we have come to expect from reflection.

Each section below will act upon a tester class to show how Method Handles work to replace or wrap around reflection calls.

The Invokable Class

The code is located at: https://github.com/c-guntur/reflection/blob/master/src/main/java/none/cgutils/InvokableClass.java.

Below is an excerpt of the code for the class that will be tested using both Reflection and Method Handles:

 1 public class InvokableClass {
 2 
 3     private String name;
 4 
 5     public InvokableClass() {
 6         this.name = "No param InvokableClass constructor";
 7     }
 8 
 9     public InvokableClass(String name) {
10         this.name = name;
11     }
12 
13     public String printStuff(String input) {
14         return "[" + this.name + "] - " + input;
15     }
16 
17     public String publicMethod(String input) {
18         return "[" + this.name + "] - Public method - " + input;
19     }
20 
21     public static String publicStaticMethod(String input) {
22         return "InvokableClass.class - Public static method " + input;
23     }
24 
25     private String privateMethod(String input) {
26         return "[" + this.name + "] - Private method " + input;
27     }
28 
29     protected String protectedMethod(String input) {
30         return "[" + this.name + "] - Protected method " + input;
31     }
32 
33     String packageProtectedMethod(String input) {
34         return "[" + this.name + "] - Package protected method " + input;
35     }
36 }

Invoking the default constructor

The code for default constructor invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/DefaultConstructorInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "[No param InvokableClass constructor] - Default constructor via reflection";
 2 
 3         try {
 4 
 5             Class invokableClassClass = (Class) Class.forName("none.cgutils.InvokableClass");
 6 
 7             InvokableClass invokableClass = invokableClassClass.getDeclaredConstructor().newInstance();
 8 
 9             assertEquals("Reflection invocation failed", expectedOutput, invokableClass.printStuff("Default constructor via reflection"));
10         } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException e) {
11 
12             fail("reflection failure: " + e.getMessage());
13         }

Method Handles

 1         String expectedOutput = "[No param InvokableClass constructor] - Default constructor via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup publicMethodHandlesLookup = MethodHandles.publicLookup();
 5 
 6         // Search for method that: have return type of void (Constructor) and accept a String parameter.
 7         MethodType methodType = MethodType.methodType(void.class);
 8 
 9         try {
10 
11             // Find the constructor based on the MethodType defined above
12             MethodHandle invokableClassConstructor = publicMethodHandlesLookup.findConstructor(InvokableClass.class, methodType);
13 
14             // Create an instance of the Invokable class by calling the exact handle.
15             InvokableClass invokableClass = (InvokableClass) invokableClassConstructor.invokeExact();
16 
17             assertEquals("Method handle invocation failed", expectedOutput, invokableClass.printStuff("Default constructor via Method Handles"));
18         } catch (NoSuchMethodException | IllegalAccessException e) {
19 
20             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
21             fail("findConstructor failure: " + e.getMessage());
22         } catch (Throwable t) {
23 
24             // invokeExact throws a Throwable (hence catching Throwable separately).
25             fail("invokeExact Failure " + t.getMessage());
26         }

Method Handles Explanation

Line 4: In the Method Handles excerpt, a lookup is setup. A Lookup is a factory to create method handles. A feature of method handles is that access restrictions are checked when the handle is created, rather than when they are used or invoked. This early access check requires that the access be evaluated against some potential caller. The Lookup acts as that caller. For this excerpt, a publicLookup is used (implies there is an alternate for non-public). A publicLookup has minimal access checks (more efficient, scope limited to public methods).

API link: https://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandles.Lookup.html

Line 7: A MethodType is used to create a signature of the method intended to be looked up. The first parameter represents the return type class while the subsequent parameters (single, array or vararg of class types) represent the method parameters. The MethodType does not associate with the name of the method and is only concerned with types involved. A void return is represented by a void.class. Primitives are represented in a similar manner.

API link: https://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodType.html

Line 10: A findConstructor is invoked on the publicLookup created earlier. The parameters are the type on which to find a constructor on, and a MethodType for picking up the right constructor signature.

Line 13: An invokeExact method ensures that the type checks defined in the MethodType are exactly matched. As in indicative by this name there are other similar methods which allow for a some fuzzyness.

API link: https://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandle.html


Invoking a parameter constructor

The code for parameterized constructor invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/ParameteredConstructorInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "[Constructor Demo] - Constructor via reflection";
 2 
 3         try {
 4 
 5             Class invokableClassClass = (Class) Class.forName("none.cgutils.InvokableClass");
 6 
 7             Constructor invokableClassConstructor = invokableClassClass.getConstructor(String.class);
 8 
 9             InvokableClass invokableClass = invokableClassConstructor.newInstance("Constructor Demo");
10 
11             assertEquals("Reflection invocation failed", expectedOutput, invokableClass.printStuff("Constructor via reflection"));
12         } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
13 
14             fail("reflection failure: " + e.getMessage());
15         }

Method Handles

 1         String expectedOutput = "[Constructor Demo] - Constructor via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup publicMethodHandlesLookup = MethodHandles.publicLookup();
 5 
 6         // Search for method that: have return type of void (Constructor) and accept a String parameter.
 7         MethodType methodType = MethodType.methodType(void.class, String.class);
 8 
 9         try {
10 
11             // Find the constructor based on the MethodType defined above
12             MethodHandle invokableClassConstructor = publicMethodHandlesLookup.findConstructor(InvokableClass.class, methodType);
13 
14             // Create an instance of the Invokable class by calling the exact handle, pass in the param value.
15             InvokableClass invokableClass = (InvokableClass) invokableClassConstructor.invokeExact("Constructor Demo");
16 
17             assertEquals("Method handles invocation failed", expectedOutput, invokableClass.printStuff("Constructor via Method Handles"));
18         } catch (NoSuchMethodException | IllegalAccessException e) {
19 
20             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
21             fail("findConstructor failure: " + e.getMessage());
22         } catch (Throwable t) {
23 
24             // invokeExact throws a Throwable (hence catching Throwable separately).
25             fail("invokeExact Failure " + t.getMessage());
26         }

Method Handles Explanation

Line 7: The MethodType has a return type of void.class (since it is a constructor) and also takes a String.class argument. This call will look for public method signatures of methods that accept a String input parameter and return a void.

Line 13: The invokeExact method has a varargs parameter signature, here a String used by the constructor is passed in


Invoking a public method

The code for public method invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/PublicMethodInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "[No param InvokableClass constructor] - Public method - via reflection";
 2 
 3         try {
 4 
 5             // Find the method on the class via a getMethod.
 6             Method publicMethod = InvokableClass.class.getMethod("publicMethod", String.class);
 7 
 8             InvokableClass invokableClass = new InvokableClass();
 9 
10             assertEquals("Reflection invocation failed", expectedOutput, publicMethod.invoke(invokableClass, "via reflection"));
11         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
12 
13             fail("reflection failure: " + e.getMessage());
14         }

Method Handles

 1         String expectedOutput = "[No param InvokableClass constructor] - Public method - via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup publicMethodHandlesLookup = MethodHandles.publicLookup();
 5 
 6         // Search for method that: have return type of String and accept a String parameter.
 7         MethodType methodType = MethodType.methodType(String.class, String.class);
 8 
 9         try {
10 
11             // Public methods are searched via findVirtual
12             MethodHandle publicMethodHandle = publicMethodHandlesLookup.findVirtual(InvokableClass.class, "publicMethod", methodType);
13 
14             InvokableClass invokableClass = new InvokableClass();
15 
16             assertEquals("Method handles invocation failed", expectedOutput, publicMethodHandle.invoke(invokableClass, "via Method Handles"));
17         } catch (NoSuchMethodException | IllegalAccessException e) {
18 
19             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
20             fail("findConstructor failure: " + e.getMessage());
21         } catch (Throwable t) {
22 
23             // invoke throws a Throwable (hence catching Throwable separately).
24             fail("invoke Failure " + t.getMessage());
25         }

Method Handles Explanation

Line 10: Public methods are looked up using a findVirtual on the Lookup. The type being looked up, the name of the method and the MethodType (return values, input parameter types) are passed to the findVirtual.


Invoking a public static method

The code for public static method invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/PublicStaticMethodInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "InvokableClass.class - Public static method via reflection";
 2 
 3         try {
 4 
 5             // Find the method on the class via a getMethod.
 6             Method publicStaticMethod = InvokableClass.class.getMethod("publicStaticMethod", String.class);
 7 
 8             assertEquals("Reflection invocation failed", expectedOutput, publicStaticMethod.invoke(InvokableClass.class, "via reflection"));
 9         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
10 
11             fail("reflection failure: " + e.getMessage());
12         }

Method Handles

 1         String expectedOutput = "InvokableClass.class - Public static method via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup publicStaticMethodHandlesLookup = MethodHandles.publicLookup();
 5 
 6         // Search for method that: have return type of String and accept a String parameter.
 7         MethodType methodType = MethodType.methodType(String.class, String.class);
 8 
 9         try {
10 
11             // Public static methods are searched via findStatic
12             MethodHandle publicStaticMethodHandle = publicStaticMethodHandlesLookup.findStatic(InvokableClass.class, "publicStaticMethod", methodType);
13 
14             assertEquals("Method handles invocation failed", expectedOutput, publicStaticMethodHandle.invoke("via Method Handles"));
15         } catch (NoSuchMethodException | IllegalAccessException e) {
16 
17             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
18             fail("findConstructor failure: " + e.getMessage());
19         } catch (Throwable t) {
20 
21             // invoke throws a Throwable (hence catching Throwable separately).
22             fail("invoke Failure " + t.getMessage());
23         }

Method Handles Explanation

Line 10: Public static methods are looked up using a findStatic on the Lookup. The type being looked up, the name of the public static method and the MethodType (return values, input parameter types) are passed to the findVirtual.


Invoking a private method

The code for private method invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/PrivateMethodInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "[No param InvokableClass constructor] - Private method via reflection";
 2 
 3         try {
 4 
 5             // Cannot call getMethod(), only use getDeclaredMethod to get private and protected methods.
 6             Method privateMethod = InvokableClass.class.getDeclaredMethod("privateMethod", String.class);
 7 
 8             // Method has to be made accessible. Not setting this will cause IllegalAccessException
 9             // Setting accessible to true causes the JVM to skip access control checks
10             privateMethod.setAccessible(true);
11 
12             InvokableClass invokableClass = new InvokableClass();
13 
14             assertEquals("Reflection invocation failed", expectedOutput, privateMethod.invoke(invokableClass, "via reflection"));
15         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
16 
17             fail("reflection failure: " + e.getMessage());
18         }

Method Handles

 1         String expectedOutput = "[No param InvokableClass constructor] - Private method via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup privateMethodHandlesLookup = MethodHandles.lookup();
 5 
 6         try {
 7 
 8             // Rely on old-fashioned reflection.
 9             Method privateMethod = InvokableClass.class.getDeclaredMethod("privateMethod", String.class);
10 
11             privateMethod.setAccessible(true);
12 
13             // Unreflect to create a method handle from a method
14             MethodHandle privateMethodHandle = privateMethodHandlesLookup.unreflect(privateMethod);
15 
16             InvokableClass invokableClass = new InvokableClass();
17 
18             assertEquals("Method handles invocation failed", expectedOutput, privateMethodHandle.invoke(invokableClass, "via Method Handles"));
19         } catch (NoSuchMethodException | IllegalAccessException e) {
20 
21             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
22             fail("findConstructor failure: " + e.getMessage());
23         } catch (Throwable t) {
24 
25             // invoke throws a Throwable (hence catching Throwable separately).
26             fail("invoke Failure " + t.getMessage());
27         }

Method Handles Explanation

Line 4: Private methods can be looked up via lookup method call that has larger find radius than the publicLookup (i.e public as well as private/protected lookup).

Line 8: There is no equivalent to finding private methods, thus reflection is still needed to get to a Method instance of the private method. As with reflection, private method instances can only be invoked only after a setAccessible is set to true.

Line 11: Private method instances looked up via reflection need to be “unreflected” to convert from the java.lang.reflect.Method to java.lang.invoke.MethodHandle. There is no direct find equivalent for private methods.


Invoking a protected method

The code for protected method invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/ProtectedMethodInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "[No param InvokableClass constructor] - Protected method via reflection";
 2 
 3         try {
 4             // Cannot call getMethod(), only use getDeclaredMethod to get private and protected methods.
 5             Method protectedMethod = InvokableClass.class.getDeclaredMethod("protectedMethod", String.class);
 6 
 7             // Method has to be made accessible. Not setting this will cause IllegalAccessException
 8             // Setting accessible to true causes the JVM to skip access control checks
 9             protectedMethod.setAccessible(true);
10 
11             InvokableClass invokableClass = new InvokableClass();
12 
13             assertEquals("Reflection invocation failed", expectedOutput, protectedMethod.invoke(invokableClass, "via reflection"));
14         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
15 
16             fail("reflection failure: " + e.getMessage());
17         }

Method Handles

 1         String expectedOutput = "[No param InvokableClass constructor] - Protected method via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup protectedMethodHandlesLookup = MethodHandles.lookup();
 5 
 6         try {
 7             // Rely on old-fashioned reflection.
 8             Method protectedMethodMethod = InvokableClass.class.getDeclaredMethod("protectedMethod", String.class);
 9             protectedMethodMethod.setAccessible(true);
10             // Unreflect to create a method handle from a method
11             MethodHandle protectedMethodHandle = protectedMethodHandlesLookup.unreflect(protectedMethodMethod);
12 
13             InvokableClass invokableClass = new InvokableClass();
14 
15             assertEquals("Reflection invocation failed", expectedOutput, protectedMethodHandle.invoke(invokableClass, "via Method Handles"));
16         } catch (NoSuchMethodException | IllegalAccessException e) {
17 
18             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
19             fail("findConstructor failure: " + e.getMessage());
20         } catch (Throwable t) {
21 
22             // invoke throws a Throwable (hence catching Throwable separately).
23             fail("invoke Failure " + t.getMessage());
24         }

Method Handles Explanation

Line 4: Protected methods can be looked up via lookup method call that has larger find radius than the publicLookup (i.e public as well as private/protected lookup).

Line 8: There is no equivalent to finding protected methods, thus reflection is still needed to get to a Method instance of the protected method. As with reflection, protected method instances can only be invoked only after a setAccessible is set to true.

Line 11: Protected method instances looked up via reflection need to be “unreflected” to convert from the java.lang.reflect.Method to java.lang.invoke.MethodHandle. There is no direct find equivalent for protected methods.


Invoking a package-protected method

The code for package-protected method invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/PackageProtectedMethodInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "[No param InvokableClass constructor] - Package protected method via reflection";
 2 
 3         try {
 4 
 5             // Cannot call getMethod(), only use getDeclaredMethod to get private and protected methods.
 6             Method packageProtectedMethod = InvokableClass.class.getDeclaredMethod("packageProtectedMethod", String.class);
 7 
 8             // Method has to be made accessible. Not setting this will cause IllegalAccessException
 9             // Setting accessible to true causes the JVM to skip access control checks
10             packageProtectedMethod.setAccessible(true);
11 
12             InvokableClass invokableClass = new InvokableClass();
13 
14             assertEquals("Reflection invocation failed", expectedOutput, packageProtectedMethod.invoke(invokableClass, "via reflection"));
15         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
16 
17             fail("reflection failure: " + e.getMessage());
18         }

Method Handles

 1         String expectedOutput = "[No param InvokableClass constructor] - Package protected method via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup packageProtectedMethodHandlesLookup = MethodHandles.lookup();
 5 
 6         try {
 7             // Rely on old-fashioned reflection.
 8             Method packageProtectedMethod = InvokableClass.class.getDeclaredMethod("packageProtectedMethod", String.class);
 9             packageProtectedMethod.setAccessible(true);
10 
11             // Unreflect to create a method handle from a method
12             MethodHandle packageProtectedMethodHandle = packageProtectedMethodHandlesLookup.unreflect(packageProtectedMethod);
13 
14             InvokableClass invokableClass = new InvokableClass();
15 
16             assertEquals("Reflection invocation failed", expectedOutput, packageProtectedMethodHandle.invoke(invokableClass, "via Method Handles"));
17         } catch (NoSuchMethodException | IllegalAccessException e) {
18 
19             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
20             fail("findConstructor failure: " + e.getMessage());
21         } catch (Throwable t) {
22 
23             // invoke throws a Throwable (hence catching Throwable separately).
24             fail("invoke Failure " + t.getMessage());
25         }

Method Handles Explanation

Line 4: Package-protected methods can be looked up via lookup method call that has larger find radius than the publicLookup (i.e public as well as private/protected lookup).

Line 8: There is no equivalent to finding package-protected methods, thus reflection is still needed to get to a Method instance of the package-protected method. As with reflection, package-protected method instances can only be invoked only after a setAccessible is set to true.

Line 11: Package-protected method instances looked up via reflection need to be “unreflected” to convert from the java.lang.reflect.Method to java.lang.invoke.MethodHandle. There is no direct find equivalent for package-protected methods.


There are a few other cool methods that will be covered in a subsequent blog.

Method Handles – Enhancements in Java Versions

    1. JSR-292https://www.jcp.org/en/jsr/detail?id=292Java 1.7 – Method Handles introduction.
    1. JEP-160http://openjdk.java.net/jeps/160Java 1.8 – Method Handles enhancements:
      • Improve performance, quality, and portability of method handles and invokedynamic.
      • Reduce the amount of assembly code in the JVM.
      • Reduce the frequency of native calls and other complex transitions of control during method handle processing.
      • Increase the leverage on JSR 292 performance of existing JVM optimization frameworks.
      • Remove low-leverage or complex structures from the JVM that serve JSR 292 only. (E.g., remove the pattern-matching “method handle walk” phase.)
      • Complete compatibility with the Java SE 7 specification for JSR 292.
      • A better reference implementation of JSR 292.
    1. JEP-274http://openjdk.java.net/jeps/274Java 9 – Method Handles enhancements (many API additions):
      • In the MethodHandles class in the java.lang.invoke package, provide new MethodHandle combinators for loops and try/finally blocks.
      • Enhance the MethodHandle and MethodHandles classes with new MethodHandle combinators for argument handling.
      • Implement new lookups for interface methods and, optionally, super constructors in the MethodHandles.Lookup class.

Complete Github project link: https://github.com/c-guntur/reflection

That’s a wrap on Java Method Handles – The NextGen Reflection (with more in a subsequent blog). Hope this post was helpful.