From 4ee655bef4cdf9e62a1b247e77754441de806f22 Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Mon, 8 Jun 2015 16:57:44 +0200 Subject: Implemented sorting using reflection, not sure it was a good idea though --- .../cardbase/comparators/CardComparator.java | 102 +++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/eu/equalparts/cardbase/comparators/CardComparator.java (limited to 'src/eu/equalparts/cardbase/comparators') diff --git a/src/eu/equalparts/cardbase/comparators/CardComparator.java b/src/eu/equalparts/cardbase/comparators/CardComparator.java new file mode 100644 index 0000000..3640c8b --- /dev/null +++ b/src/eu/equalparts/cardbase/comparators/CardComparator.java @@ -0,0 +1,102 @@ +package eu.equalparts.cardbase.comparators; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Comparator; + +import eu.equalparts.cardbase.Cardbase; +import eu.equalparts.cardbase.data.Card; + +/** + * I'm new to this reflection business, so bear with me. + *

+ * The idea here is to avoid having to write one class + * for each comparable field in {@code Card}. The program + * can dynamically instantiate them as cards are compared + * by different fields. + *

+ * This class uses reflection to determine if the specified + * field is comparable with itself upon construction, and throws + * an {@code IllegalArgumentException} if that is not the case. + * + * @author Eduardo Pedroni + * + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public class CardComparator implements Comparator { + + /** + * The field being compared. + */ + private Field fieldToCompare; + + /** + * Creates a new comparator for the specified field only. This class + * will only be constructed successfully if the field comes from + * {@code Card} and can be compared to itself (i.e. implements + * {@code Comparable} where T is its own type. + *
+ * For reference, {@code String} and {@code Integer} are both self comparable. + * + * @param fieldToCompare the field this comparator will use to compare cards, as declared in {@code Card}. + */ + public CardComparator(Field fieldToCompare) { + if (fieldToCompare.getDeclaringClass().equals(Card.class) && + isSelfComparable(fieldToCompare.getType())) { + + this.fieldToCompare = fieldToCompare; + } else { + System.out.println(fieldToCompare.isAccessible()); + System.out.println(fieldToCompare.getDeclaringClass().equals(Card.class)); + System.out.println(isSelfComparable(fieldToCompare.getType())); + throw new IllegalArgumentException("The field provided is not valid."); + } + } + + @Override + public int compare(Card o1, Card o2) { + try { + /* + * we've already checked that the field is self comparable, + * so we are now free to cast to whatever type it is and compare. + */ + Comparable field1 = (Comparable) fieldToCompare.get(o1); + Comparable field2 = (Comparable) fieldToCompare.get(o2); + + return field1.compareTo(field2); + + } catch (IllegalArgumentException e) { + System.out.println("Error: class Card does not define field" + fieldToCompare.getName() + "."); + if (Cardbase.DEBUG) e.printStackTrace(); + } catch (IllegalAccessException e) { + System.out.println("Error: field " + fieldToCompare.getName() + " in Card is not visible."); + if (Cardbase.DEBUG) e.printStackTrace(); + } + + // not comparable, this should never happen + return 0; + } + + /** + * Use reflection to determine if the specified class can be compared with itself. + * + * @param type the type to analyse. + * @return true if the type can be compared to itself using {@code compareTo()}, false otherwise. + */ + private boolean isSelfComparable(Class type) { + + // go through all interfaces implemented by this class + for (Type implementedInterface : type.getGenericInterfaces()) { + // check if any parameterised interface found is "Comparable" + if (implementedInterface instanceof ParameterizedType) { + ParameterizedType genericInterface = (ParameterizedType) implementedInterface; + if (genericInterface.getRawType().equals(Comparable.class)) { + // check that the type argument of comparable is the same as the field type itself + return genericInterface.getActualTypeArguments()[0].equals(type); + } + } + } + return false; + } +} -- cgit v1.2.3