Skip to content

Instantly share code, notes, and snippets.

@heruan
Last active November 22, 2017 11:02
Show Gist options
  • Save heruan/f52d2195471ac08a66a7c44c519b8730 to your computer and use it in GitHub Desktop.
Save heruan/f52d2195471ac08a66a7c44c519b8730 to your computer and use it in GitHub Desktop.
import java.util.Comparator;
import java.util.Optional;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class CustomComparatorTest {
static class CustomComparator<T> implements Comparator<T> {
@Override
public int compare(T arg0, T arg1) {
return 0;
}
@Override
public Comparator<T> thenComparing(Comparator<? super T> arg0) {
return new CustomComparator<>();
}
}
static <T> Optional<Comparator<T>> instanceOfCustomComparator(Comparator<T> comparator) {
if (comparator instanceof CustomComparator) {
return Optional.of(comparator);
} else if (LambdaReflectionUtils.isMethodReference(comparator)) {
Comparator<T> referencedMethodOwner = LambdaReflectionUtils.getReferencedMethodOwner(comparator);
return instanceOfCustomComparator(referencedMethodOwner);
} else if (LambdaReflectionUtils.isReverseComparator(comparator)) {
Comparator<T> originalComparator = LambdaReflectionUtils.getOriginalComparator(comparator);
return instanceOfCustomComparator(originalComparator);
} else if (LambdaReflectionUtils.isThenComparingComparator(comparator)) {
Comparator<T> firstComparator = LambdaReflectionUtils.getThenComparingFirstComparator(comparator);
Optional<Comparator<T>> optionalFirstComparator = instanceOfCustomComparator(firstComparator);
if (optionalFirstComparator.isPresent()) {
Comparator<T> firstCustomComparator = optionalFirstComparator.get();
Comparator<T> secondComparator = LambdaReflectionUtils.getThenComparingSecondComparator(comparator);
Optional<Comparator<T>> optionalSecondComparator = instanceOfCustomComparator(secondComparator);
if (optionalSecondComparator.isPresent()) {
Comparator<T> secondCustomComparator = optionalSecondComparator.get();
return Optional.of(firstCustomComparator.thenComparing(secondCustomComparator));
}
}
}
return Optional.empty();
}
@Test
public void identifiesCustomComparator() {
CustomComparator<String> comparator = new CustomComparator<>();
Optional<Comparator<String>> instanceOfCustomComparator = instanceOfCustomComparator(comparator);
Assertions.assertTrue(instanceOfCustomComparator.isPresent());
Assertions.assertTrue(instanceOfCustomComparator.get() instanceof CustomComparator);
}
@Test
public void identifiesMethodReference() {
CustomComparator<String> comparator = new CustomComparator<>();
Optional<Comparator<String>> instanceOfCustomComparator = instanceOfCustomComparator(comparator::compare);
Assertions.assertTrue(instanceOfCustomComparator.isPresent());
Assertions.assertTrue(instanceOfCustomComparator.get() instanceof CustomComparator);
}
@Test
public void identifiesThenComparingWithMethodReference() {
CustomComparator<String> comparator = new CustomComparator<>();
Comparator<String> methodReference = comparator::compare;
Optional<Comparator<String>> instanceOfCustomComparator = instanceOfCustomComparator(
methodReference.thenComparing(methodReference));
Assertions.assertTrue(instanceOfCustomComparator.isPresent());
System.out.println(instanceOfCustomComparator.get().getClass().getName());
Assertions.assertTrue(instanceOfCustomComparator.get() instanceof CustomComparator);
}
@Test
public void identifiesThenComparingMethodReferenceWithMethodReference() {
CustomComparator<String> comparator = new CustomComparator<>();
Comparator<String> methodReference = comparator::compare;
Optional<Comparator<String>> instanceOfCustomComparator = instanceOfCustomComparator(
methodReference.thenComparing(methodReference)::compare);
Assertions.assertTrue(instanceOfCustomComparator.isPresent());
Assertions.assertTrue(instanceOfCustomComparator.get() instanceof CustomComparator);
}
@Test
public void identifiesMultipleThenComparingMethodReferenceWithMethodReference() {
CustomComparator<String> comparator = new CustomComparator<>();
Comparator<String> methodReference = comparator::compare;
Comparator<String> multipleThenComparing = methodReference.thenComparing(methodReference)::compare;
Optional<Comparator<String>> instanceOfCustomComparator = instanceOfCustomComparator(
multipleThenComparing.thenComparing(multipleThenComparing)::compare);
Assertions.assertTrue(instanceOfCustomComparator.isPresent());
Assertions.assertTrue(instanceOfCustomComparator.get() instanceof CustomComparator);
}
@Test
public void identifiesMultipleThenComparingAndReversedMethodReferenceWithMethodReference() {
CustomComparator<String> comparator = new CustomComparator<>();
Comparator<String> methodReference = comparator::compare;
Comparator<String> multipleThenComparing = methodReference
.thenComparing(methodReference.reversed()::compare)::compare;
Optional<Comparator<String>> instanceOfCustomComparator = instanceOfCustomComparator(
multipleThenComparing.thenComparing(multipleThenComparing.reversed()::compare).reversed()::compare);
Assertions.assertTrue(instanceOfCustomComparator.isPresent());
Assertions.assertTrue(instanceOfCustomComparator.get() instanceof CustomComparator);
}
}
public class LambdaReflectionUtils {
private static final String REFERENCED_METHOD_OWNER_FIELD = "arg$1";
private static final String THEN_COMPARING_OTHER_FIELD = "arg$2";
private static final String REVERSE_COMPARATOR_ORIGINAL_FIELD = "cmp";
public static boolean isMethodReference(Object target) {
try {
target.getClass().getDeclaredField(REFERENCED_METHOD_OWNER_FIELD);
try {
target.getClass().getDeclaredField(THEN_COMPARING_OTHER_FIELD);
} catch (NoSuchFieldException e) {
return true;
}
return false;
} catch (NoSuchFieldException e) {
return false;
} catch (SecurityException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
public static <T> T getReferencedMethodOwner(Object methodReference) {
try {
Field referencedMethodOwnerField = methodReference.getClass().getDeclaredField(REFERENCED_METHOD_OWNER_FIELD);
referencedMethodOwnerField.setAccessible(true);
return (T) referencedMethodOwnerField.get(methodReference);
} catch (NoSuchFieldException e) {
throw new IllegalArgumentException("Not a method reference.", e);
} catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static <T> boolean isReverseComparator(Comparator<T> comparator) {
return comparator.getClass().getName().contains("ReverseComparator");
}
@SuppressWarnings("unchecked")
public static <T> Comparator<T> getOriginalComparator(Comparator<T> reverseComparator) {
try {
Field originalComparatorField = reverseComparator.getClass().getDeclaredField(REVERSE_COMPARATOR_ORIGINAL_FIELD);
originalComparatorField.setAccessible(true);
return (Comparator<T>) originalComparatorField.get(reverseComparator);
} catch (NoSuchFieldException e) {
throw new IllegalArgumentException("Not a reversed comparator.", e);
} catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static <T> boolean isThenComparingComparator(Comparator<T> comparator) {
try {
comparator.getClass().getDeclaredField(THEN_COMPARING_OTHER_FIELD);
return true;
} catch (NoSuchFieldException e) {
return false;
} catch (SecurityException e) {
throw new RuntimeException(e);
}
}
public static <T> Comparator<T> getThenComparingFirstComparator(Comparator<T> thenComparingComparator) {
return getThenComparingComparator(thenComparingComparator, REFERENCED_METHOD_OWNER_FIELD);
}
public static <T> Comparator<T> getThenComparingSecondComparator(Comparator<T> thenComparingComparator) {
return getThenComparingComparator(thenComparingComparator, THEN_COMPARING_OTHER_FIELD);
}
@SuppressWarnings("unchecked")
private static <T> Comparator<T> getThenComparingComparator(Comparator<T> thenComparingComparator, String fieldName) {
try {
Field firstComparatorField = thenComparingComparator.getClass().getDeclaredField(fieldName);
firstComparatorField.setAccessible(true);
return (Comparator<T>) firstComparatorField.get(thenComparingComparator);
} catch (NoSuchFieldException e) {
throw new IllegalArgumentException("Not a thenComparing comparator.", e);
} catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment