Skip to content

Commit

Permalink
Support for lambdas with marker interfaces
Browse files Browse the repository at this point in the history
Fixes #62
  • Loading branch information
luontola committed Jul 19, 2015
1 parent bc192b5 commit 4d101af
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 1 deletion.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@ optimizations to that mechanism may break Retrolambda.
Version History
---------------

### Upcoming

- Support for lambdas with marker interfaces
([Issue #62](https://github.com/orfjackal/retrolambda/issues/62))

### Retrolambda 2.0.4 (2015-07-08)

- Fixed a compile error when calling default methods from another module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ public interface LambdaConstant {
Callable<String> LAMBDA = () -> "foo";
}

@Test
public void lambdas_with_marker_interfaces_due_to_intersection_types() throws Exception {
// We must use something other than java.io.Serializable as the marker interface,
// because serializable lambdas are signified by a flag to LambdaMetafactory.altMetafactory
Callable<String> lambda = (Callable<String> & Cloneable) () -> "foo";

assertThat(lambda, is(instanceOf(Cloneable.class)));
assertThat(lambda.call(), is("foo"));
}

@Test
public void method_references_to_virtual_methods() throws Exception {
String foo = "foo";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ public class Types {

public static Object asmToJdkType(Object arg, ClassLoader classLoader, MethodHandles.Lookup caller) throws Exception {
if (arg instanceof Type) {
return toMethodType((Type) arg, classLoader);
Type type = (Type) arg;
if (type.getSort() == Type.METHOD) {
return toMethodType(type, classLoader);
} else if (type.getSort() == Type.OBJECT) {
return toClass(type, classLoader);
} else {
throw new IllegalArgumentException("Unsupported type: " + type);
}
} else if (arg instanceof Handle) {
return toMethodHandle((Handle) arg, classLoader, caller);
} else {
Expand All @@ -26,6 +33,10 @@ public static MethodType toMethodType(Type type, ClassLoader classLoader) {
return MethodType.fromMethodDescriptorString(type.getInternalName(), classLoader);
}

private static Class<?> toClass(Type type, ClassLoader classLoader) throws ClassNotFoundException {
return classLoader.loadClass(type.getInternalName().replace('/', '.'));
}

public static MethodHandle toMethodHandle(Handle handle, ClassLoader classLoader, MethodHandles.Lookup lookup) throws Exception {
MethodType type = MethodType.fromMethodDescriptorString(handle.getDesc(), classLoader);
Class<?> owner = classLoader.loadClass(handle.getOwner().replace('/', '.'));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright © 2013-2015 Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

package net.orfjackal.retrolambda.lambdas;

import org.junit.Test;
import org.objectweb.asm.*;

import java.lang.invoke.*;
import java.util.function.Predicate;

import static net.orfjackal.retrolambda.lambdas.Types.asmToJdkType;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

@SuppressWarnings("UnnecessaryLocalVariable")
public class TypesTest {

private ClassLoader classLoader = getClass().getClassLoader();
private MethodHandles.Lookup lookup = MethodHandles.lookup();

@Test
public void asmToJdkType_MethodType() throws Exception {
Type input = Type.getMethodType("(I)Ljava/util/function/Predicate;");
MethodType output = MethodType.methodType(Predicate.class, int.class);

assertThat(asmToJdkType(input, classLoader, lookup), is(output));
}

@Test
public void asmToJdkType_MethodHandle() throws Exception {
Handle input = new Handle(Opcodes.H_INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;");
MethodHandle output = lookup.findStatic(String.class, "valueOf", MethodType.methodType(String.class, int.class));

assertThat(asmToJdkType(input, classLoader, lookup).toString(), is(output.toString()));
}

@Test
public void asmToJdkType_Class() throws Exception {
Type input = Type.getType(String.class);
Class<?> output = String.class;

assertThat(asmToJdkType(input, classLoader, lookup), is(equalTo(output)));
}

@Test
public void asmToJdkType_everything_else() throws Exception {
String input = "foo";
String output = input;

assertThat(asmToJdkType(input, classLoader, lookup), is(output));
}
}

0 comments on commit 4d101af

Please # to comment.