[java] Java equivalent to C# extension methods

I am looking to implement a functionality in a list of object as I would in C# using an extension method.

Something like this:

List<DataObject> list;
// ... List initialization.
list.getData(id);

How do I do that in Java?

This question is related to java extension-methods

The answer is


The XTend language — which is a super-set of Java, and compiles to Java source code1 — supports this.


Bit late to the party on this question, but in case anyone finds it useful I just created a subclass:

public class ArrayList2<T> extends ArrayList<T> 
{
    private static final long serialVersionUID = 1L;

    public T getLast()
    {
        if (this.isEmpty())
        {
            return null;
        }
        else
        {       
            return this.get(this.size() - 1);
        }
    }
}

Manifold provides Java with C#-style extension methods and several other features. Unlike other tools, Manifold has no limitations and does not suffer from issues with generics, lambdas, IDE etc. Manifold provides several other features such as F#-style custom types, TypeScript-style structural interfaces, and Javascript-style expando types.

Additionally, IntelliJ provides comprehensive support for Manifold via the Manifold plugin.

Manifold is an open source project available on github.


We can simulate the implementation of C# extension methods in Java by using the default method implementation available since Java 8. We start by defining an interface that will allow us to access the support object via a base() method, like so:

public interface Extension<T> {

    default T base() {
        return null;
    }
}

We return null since interfaces cannot have state, but this has to be fixed later via a proxy.

The developer of extensions would have to extend this interface by a new interface containing extension methods. Let's say we want to add a forEach consumer on List interface:

public interface ListExtension<T> extends Extension<List<T>> {

    default void foreach(Consumer<T> consumer) {
        for (T item : base()) {
            consumer.accept(item);
        }
    }

}

Because we extend the Extension interface, we can call base() method inside our extension method to access the support object we attach to.

The Extension interface must have a factory method which will create an extension of a given support object:

public interface Extension<T> {

    ...

    static <E extends Extension<T>, T> E create(Class<E> type, T instance) {
        if (type.isInterface()) {
            ExtensionHandler<T> handler = new ExtensionHandler<T>(instance);
            List<Class<?>> interfaces = new ArrayList<Class<?>>();
            interfaces.add(type);
            Class<?> baseType = type.getSuperclass();
            while (baseType != null && baseType.isInterface()) {
                interfaces.add(baseType);
                baseType = baseType.getSuperclass();
            }
            Object proxy = Proxy.newProxyInstance(
                    Extension.class.getClassLoader(),
                    interfaces.toArray(new Class<?>[interfaces.size()]),
                    handler);
            return type.cast(proxy);
        } else {
            return null;
        }
    }
}

We create a proxy that implements the extension interface and all the interface implemented by the type of the support object. The invocation handler given to the proxy would dispatch all the calls to the support object, except for the "base" method, which must return the support object, otherwise its default implementation is returning null:

public class ExtensionHandler<T> implements InvocationHandler {

    private T instance;

    private ExtensionHandler(T instance) {
        this.instance = instance;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        if ("base".equals(method.getName())
                && method.getParameterCount() == 0) {
            return instance;
        } else {
            Class<?> type = method.getDeclaringClass();
            MethodHandles.Lookup lookup = MethodHandles.lookup()
                .in(type);
            Field allowedModesField = lookup.getClass().getDeclaredField("allowedModes");
            makeFieldModifiable(allowedModesField);
            allowedModesField.set(lookup, -1);
            return lookup
                .unreflectSpecial(method, type)
                .bindTo(proxy)
                .invokeWithArguments(args);
        }
    }

    private static void makeFieldModifiable(Field field) throws Exception {
        field.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField
                .setInt(field, field.getModifiers() & ~Modifier.FINAL);
    }

}

Then, we can use the Extension.create() method to attach the interface containing the extension method to the support object. The result is an object which can be casted to the extension interface by which we can still access the support object calling the base() method. Having the reference casted to the extension interface, we now can safely call the extension methods that can have access to the support object, so that now we can attach new methods to the existing object, but not to its defining type:

public class Program {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("a", "b", "c");
        ListExtension<String> listExtension = Extension.create(ListExtension.class, list);
        listExtension.foreach(System.out::println);
    }

}

So, this is a way we can simulate the ability to extend objects in Java by adding new contracts to them, which allow us to call additional methods on the given objects.

Below you may find the code of the Extension interface:

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

public interface Extension<T> {

    public class ExtensionHandler<T> implements InvocationHandler {

        private T instance;

        private ExtensionHandler(T instance) {
            this.instance = instance;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            if ("base".equals(method.getName())
                    && method.getParameterCount() == 0) {
                return instance;
            } else {
                Class<?> type = method.getDeclaringClass();
                MethodHandles.Lookup lookup = MethodHandles.lookup()
                    .in(type);
                Field allowedModesField = lookup.getClass().getDeclaredField("allowedModes");
                makeFieldModifiable(allowedModesField);
                allowedModesField.set(lookup, -1);
                return lookup
                    .unreflectSpecial(method, type)
                    .bindTo(proxy)
                    .invokeWithArguments(args);
            }
        }

        private static void makeFieldModifiable(Field field) throws Exception {
            field.setAccessible(true);
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        }

    }

    default T base() {
        return null;
    }

    static <E extends Extension<T>, T> E create(Class<E> type, T instance) {
        if (type.isInterface()) {
            ExtensionHandler<T> handler = new ExtensionHandler<T>(instance);
            List<Class<?>> interfaces = new ArrayList<Class<?>>();
            interfaces.add(type);
            Class<?> baseType = type.getSuperclass();
            while (baseType != null && baseType.isInterface()) {
                interfaces.add(baseType);
                baseType = baseType.getSuperclass();
            }
            Object proxy = Proxy.newProxyInstance(
                    Extension.class.getClassLoader(),
                    interfaces.toArray(new Class<?>[interfaces.size()]),
                    handler);
            return type.cast(proxy);
        } else {
            return null;
        }
    }

}

Technically C# Extension have no equivalent in Java. But if you do want to implement such functions for a cleaner code and maintainability, you have to use Manifold framework.

package extensions.java.lang.String;

import manifold.ext.api.*;

@Extension
public class MyStringExtension {

  public static void print(@This String thiz) {
    System.out.println(thiz);
  }

  @Extension
  public static String lineSeparator() {
    return System.lineSeparator();
  }
}

Java 8 now supports default methods, which are similar to C#'s extension methods.


It looks like there is some small chance that Defender Methods (i.e. default methods) might make it into Java 8. However, as far as I understand them, they only allow the author of an interface to retroactively extend it, not arbitrary users.

Defender Methods + Interface Injection would then be able to fully implement C#-style extension methods, but AFAICS, Interface Injection isn't even on the Java 8 road-map yet.


One could be use the decorator object-oriented design pattern. An example of this pattern being used in Java's standard library would be the DataOutputStream.

Here's some code for augmenting the functionality of a List:

public class ListDecorator<E> implements List<E>
{
    public final List<E> wrapee;

    public ListDecorator(List<E> wrapee)
    {
        this.wrapee = wrapee;
    }

    // implementation of all the list's methods here...

    public <R> ListDecorator<R> map(Transform<E,R> transformer)
    {
        ArrayList<R> result = new ArrayList<R>(size());
        for (E element : this)
        {
            R transformed = transformer.transform(element);
            result.add(transformed);
        }
        return new ListDecorator<R>(result);
    }
}

P.S. I'm a big fan of Kotlin. It has extension methods and also runs on the JVM.


Project Lombok provides an annotation @ExtensionMethod that can be used to achieve the functionality you are asking for.


You can create a C# like extension/helper method by (RE) implementing the Collections interface and adding- example for Java Collection:

public class RockCollection<T extends Comparable<T>> implements Collection<T> {
private Collection<T> _list = new ArrayList<T>();

//###########Custom extension methods###########

public T doSomething() {
    //do some stuff
    return _list  
}

//proper examples
public T find(Predicate<T> predicate) {
    return _list.stream()
            .filter(predicate)
            .findFirst()
            .get();
}

public List<T> findAll(Predicate<T> predicate) {
    return _list.stream()
            .filter(predicate)
            .collect(Collectors.<T>toList());
}

public String join(String joiner) {
    StringBuilder aggregate = new StringBuilder("");
    _list.forEach( item ->
        aggregate.append(item.toString() + joiner)
    );
    return aggregate.toString().substring(0, aggregate.length() - 1);
}

public List<T> reverse() {
    List<T> listToReverse = (List<T>)_list;
    Collections.reverse(listToReverse);
    return listToReverse;
}

public List<T> sort(Comparator<T> sortComparer) {
    List<T> listToReverse = (List<T>)_list;
    Collections.sort(listToReverse, sortComparer);
    return listToReverse;
}

public int sum() {
    List<T> list = (List<T>)_list;
    int total = 0;
    for (T aList : list) {
        total += Integer.parseInt(aList.toString());
    }
    return total;
}

public List<T> minus(RockCollection<T> listToMinus) {
    List<T> list = (List<T>)_list;
    int total = 0;
    listToMinus.forEach(list::remove);
    return list;
}

public Double average() {
    List<T> list = (List<T>)_list;
    Double total = 0.0;
    for (T aList : list) {
        total += Double.parseDouble(aList.toString());
    }
    return total / list.size();
}

public T first() {
    return _list.stream().findFirst().get();
            //.collect(Collectors.<T>toList());
}
public T last() {
    List<T> list = (List<T>)_list;
    return list.get(_list.size() - 1);
}
//##############################################
//Re-implement existing methods
@Override
public int size() {
    return _list.size();
}

@Override
public boolean isEmpty() {
    return _list == null || _list.size() == 0;
}

There is no extension methods in Java, but you can have it by manifold as below,

You define "echo" method for strings by below sample,

@Extension
public class MyStringExtension {
    public static void echo(@This String thiz) {
        System.out.println(thiz);
    }
}

And after that, you can use this method (echo) for strings anywhere like,

"Hello World".echo();   //prints "Hello World"
"Welcome".echo();       //prints "Welcome"
String name = "Jonn";
name.echo();            //prints "John"


You can also, of course, have parameters like,

@Extension
public class MyStringExtension {
    public static void echo(@This String thiz, String suffix) {
        System.out.println(thiz + " " + suffix);
    }
}

And use like this,

"Hello World".echo("programming");   //prints "Hello World programming"
"Welcome".echo("2021");              //prints "Welcome 2021"
String name = "Jonn";
name.echo("Conor");                  //prints "John Conor"

You can take a look at this sample also, Manifold-sample


Java does not have such feature. Instead you can either create regular subclass of your list implementation or create anonymous inner class:

List<String> list = new ArrayList<String>() {
   public String getData() {
       return ""; // add your implementation here. 
   }
};

The problem is to call this method. You can do it "in place":

new ArrayList<String>() {
   public String getData() {
       return ""; // add your implementation here. 
   }
}.getData();

Extension methods are not just static method and not just convenience syntax sugar, in fact they are quite powerful tool. The main thing there is ability to override different methods based on different generic’s parameters instantiation. This is similar to Haskell’s type classes, and in fact, it looks like they are in C# to support C#’s Monads (i.e. LINQ). Even dropping LINQ syntax, I still don’t know any way to implement similar interfaces in Java.

And I don’t think it is possible to implement them in Java, because of Java’s type erasure semantics of generics parameters.


Another option is to use ForwardingXXX classes from google-guava library.