In object-oriented computer programming, an extension method is a method added to an object after the original object was compiled. Extension methods are features of some object-oriented programming languages. There is no syntactic difference between calling an extension method and calling a method declared in the type definition. Extension methods are features of numerous languages including C#, Java via Manifold or Lombok, JavaScript, Ruby, Smalltalk, Kotlin, Visual Basic.NET, etc. But in this article, we will only focus on Java and will learn how we can implement extension methods in Java. In Java we can add extension methods via Manifold, a jar file (Manifold is a Java compiler plugin) we add to our project’s classpath. A Java extension method is declared static in an @Extension class where the first argument has the same type as the extended class and is annotated with @This.
Let’s understand how we can implement the Extension method in java with the help of one scenario. Suppose we have one JSON file (student-list.json) which contains the list of students and we want to read the content and store it in a String variable. As a developer, we hope for something like this:
student-list.json
{ { "name":"Bishal Dubey", "degree":"Bachelor of Technology", "specialization":"Computer Science & Engineering", "college":"College Of Engineering, Bhubaneswar", "batch":"2013-2017", "dob":"11-11-1994" }, { "name":"Tanu Jain", "degree":"Bachelor of Technology", "specialization":"Computer Science & Engineering", "college":"Jaypee Institute of Engineering and Technology, Guna", "batch":"2015-2019", "dob":"27-07-1996" } }
Java
import java.io.*; class GFG { public static void main(String[] args) { File file = new File( "student-list.json" ); String content = file.readText(); // But readText() method is not // available for file object } } |
Regrettably, when we will type the file. in our IDE then we will get to know that no such method i.e. readText() exists. Next, we will implement the logic to read the text/context of the file. As a good developers, We want to save ourselves and others from duplicating this effort, so we will move this code to a Util library i.e. a separate class like below:
Java
package com.gfg.technicalscripter; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class FileReaderUtility { private static String readText(File file) throws FileNotFoundException { InputStream targetStream = new FileInputStream(file); StringBuffer sb = new StringBuffer(); try { BufferedReader br = new BufferedReader( new InputStreamReader(targetStream)); String line; while ((line = br.readLine()) != null ) { sb.append(line); } br.close(); } catch (IOException e) { e.printStackTrace(); } return sb.toString(); } } |
Now, we can write the code as below :
Java
package com.gfg.technicalscripter; import java.io.File; import java.io.FileNotFoundException; public class App { public static void main(String[] args) throws FileNotFoundException { File file = new File( "src/main/java/student-list.json" ); String content = FileReaderUtility.readText(file); System.out.print(content); // Now we will get the correct output } } |
Is this as good as it gets? We deserve a more user-friendly method i.e. how we will get to know that we have one separate utility class which has the readText() method and it returns the content in string format. We should have readText() method as part of the file only. So we can easily call file.readText() to get the content of the file. This readText() is better suited and more easily discoverable as an instance method directly on File. This is where a feature commonly known in the language community as Extension Methods comes into the picture. Before implementing the Extension Methods, we have to add the Manifold extension library to our project.
XML
< dependency > < groupId >systems.manifold</ groupId > < artifactId >manifold-ext</ artifactId > < version >2022.1.21</ version > < scope >provided</ scope > </ dependency > |
Manifold fully implements Extension Methods for Java via Extension Classes:
Java
package extensions.java.io.File; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import manifold.ext.rt.api.Extension; import manifold.ext.rt.api.This; @Extension public class FileExtension { public static String readText( @This File file) throws FileNotFoundException { InputStream targetStream = new FileInputStream(file); StringBuffer sb = new StringBuffer(); try { BufferedReader br = new BufferedReader( new InputStreamReader(targetStream)); String line; while ((line = br.readLine()) != null ) { sb.append(line); } br.close(); } catch (IOException e) { e.printStackTrace(); } return sb.toString(); } } |
Now, we can call readText() method directly on the file instance like below and we will get the same output as via FileReaderUtility readText() method.
Java
package com.gfg.technicalscripter; import java.io.File; import java.io.FileNotFoundException; public class App { public static void main(String[] args) throws FileNotFoundException { File file = new File( "src/main/java/student-list.json" ); String content = file.readText(); System.out.println(content); } } |
Project Structure:
Extensions eliminate/reduce a lot of intermediate/boiler-plate code such as “Util” and “Manager” libraries as well as Factory classes. Extension methods naturally promote higher levels of object orientation, which result in more readable and maintainable code.