Last active
November 22, 2017 11:02
-
-
Save heruan/f52d2195471ac08a66a7c44c519b8730 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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