|
|
@@ -0,0 +1,118 @@
|
|
|
+/*
|
|
|
+ * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
+ * @copyright Ranides Atterwim
|
|
|
+ * @license WTFPL
|
|
|
+ * @url http://ranides.net/projects/assira
|
|
|
+ */
|
|
|
+package net.ranides.assira.generic;
|
|
|
+
|
|
|
+import java.lang.reflect.ParameterizedType;
|
|
|
+import java.lang.reflect.Type;
|
|
|
+import net.ranides.assira.reflection.IClass;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Klasa przekazująca dalej informację o klasie w genericu. Prosty przykład problemu,
|
|
|
+ * który rozwiązuje TypeToken:
|
|
|
+ * <blockquote><pre>
|
|
|
+ * List<T> makeList(Class<T> clazz, int size) {
|
|
|
+ * return new ArrayList<T>(size);
|
|
|
+ * }
|
|
|
+ *
|
|
|
+ * List<T> copyList(List<T> source) {
|
|
|
+ * List<T> target = makeList( ? , source.size());
|
|
|
+ * for(T item : source) target.add(item);
|
|
|
+ * return target;
|
|
|
+ * }
|
|
|
+ * </pre></blockquote>
|
|
|
+ *
|
|
|
+ * {@code makeList} pobiera instancję {@code Class<T>} bo jakoś musi dostać to nieszczęsne T.
|
|
|
+ * Problem w tym, że copyList już takiej instancji nie dostaje - a nie da się utworzyć {@code new Class<T>()}
|
|
|
+ * żeby jej przekazać. Oczywiście {@code new TypeToken<T>()} jest legalne. I tylko z tego
|
|
|
+ * właśnie powodu klasa została napisana. Rozszerzony i poprawiony kod:
|
|
|
+ *
|
|
|
+ * <blockquote><pre>
|
|
|
+ * List<T> makeList(Class<T> clazz, int size) {
|
|
|
+ * return new ArrayList<T>(size);
|
|
|
+ * }
|
|
|
+ *
|
|
|
+ * List<T> makeList(TypeToken<T> token, int size) {
|
|
|
+ * return new ArrayList<T>(size);
|
|
|
+ * }
|
|
|
+ *
|
|
|
+ * List<T> copyList(List<T> source) {
|
|
|
+ * List<T> target = makeList( new TypeToken<T>(){} , source.size());
|
|
|
+ * for(T item : source) target.add(item);
|
|
|
+ * return target;
|
|
|
+ * }
|
|
|
+ * </pre></blockquote>
|
|
|
+ *
|
|
|
+ * <p>
|
|
|
+ * Uwaga. Klasa potrafi porządnie wydedukować instancję {@code Class<T>}.
|
|
|
+ * Rozszerzenie podpatrzone z biblioteki <a href="http://wiki.fasterxml.com/JacksonHome">Jackson JSON Processor</a>
|
|
|
+ * </p>
|
|
|
+ * @param <T> typ, który chcemy przekazać dalej
|
|
|
+ *
|
|
|
+ * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
+ */
|
|
|
+public abstract class TypeToken<T> implements Comparable<TypeToken<T>> {
|
|
|
+
|
|
|
+ private final Type type;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Tworzy nową instancję klasy TypeToken. Możliwe i sensowne tylko w formie
|
|
|
+ * utworzenia nowej klasy anonimowej, parametryzowanej typem, który chcemy
|
|
|
+ * przekazać / przechować / wydedukować:
|
|
|
+ * <pre>
|
|
|
+ * {@code new TypeToken<Integer>(){ } }
|
|
|
+ * </pre>
|
|
|
+ *
|
|
|
+ */
|
|
|
+ protected TypeToken()
|
|
|
+ {
|
|
|
+ Type superClass = getClass().getGenericSuperclass();
|
|
|
+ if (superClass instanceof Class<?>) { // sanity check, should never happen
|
|
|
+ throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
|
|
|
+ }
|
|
|
+ /* 22-Dec-2008, tatu: Not sure if this case is safe -- I suspect
|
|
|
+ * it is possible to make it fail?
|
|
|
+ * But let's deal with specific
|
|
|
+ * case when we know an actual use case, and thereby suitable
|
|
|
+ * workarounds for valid case(s) and/or error to throw
|
|
|
+ * on invalid one(s).
|
|
|
+ */
|
|
|
+ type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ protected TypeToken(Class<?> type) {
|
|
|
+ this.type = type;
|
|
|
+ }
|
|
|
+
|
|
|
+ public IClass type() {
|
|
|
+ return IClass.typefor(type);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The only reason we define this method (and require implementation
|
|
|
+ * of <code>Comparable</code>) is to prevent constructing a
|
|
|
+ * reference without type information.
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int compareTo(TypeToken<T> that) {
|
|
|
+ return type().compareTo(that.type());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int hashCode() {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean equals(Object object) {
|
|
|
+ if(!(object instanceof TypeToken<?>)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ TypeToken<?> that = (TypeToken<?>)object;
|
|
|
+ return type().equals(that.type());
|
|
|
+ }
|
|
|
+
|
|
|
+}
|