Ranides Atterwim 10 лет назад
Родитель
Сommit
3820ef7147
2 измененных файлов с 119 добавлено и 0 удалено
  1. 1 0
      assira/pom.xml
  2. 118 0
      assira/src/main/java/net/ranides/assira/generic/TypeToken.java

+ 1 - 0
assira/pom.xml

@@ -32,6 +32,7 @@
                                 <include>net/ranides/assira/awt/ImageLoader*</include>
                                 <include>net/ranides/assira/awt/AWTInvoker*</include>
                                 <include>net/ranides/assira/generic/SerializationUtils*</include>
+                                <include>net/ranides/assira/generic/TypeToken*</include>
                                 <include>net/ranides/assira/collection/arrays/NativeArrayUtils</include>
                                 <include>net/ranides/assira/collection/arrays/ArrayUtils</include>
                                 <include>net/ranides/assira/collection/iterators/IteratorUtils*</include>

+ 118 - 0
assira/src/main/java/net/ranides/assira/generic/TypeToken.java

@@ -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&lt;T&gt; makeList(Class&lt;T&gt; clazz, int size) {
+ *     return new ArrayList&lt;T&gt;(size);
+ * }
+ *
+ * List&lt;T&gt; copyList(List&lt;T&gt; source) {
+ *     List&lt;T&gt; 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&lt;T&gt; makeList(Class&lt;T&gt; clazz, int size) {
+ *     return new ArrayList&lt;T&gt;(size);
+ * }
+ *
+ * List&lt;T&gt; makeList(TypeToken&lt;T&gt; token, int size) {
+ *     return new ArrayList&lt;T&gt;(size);
+ * }
+ *
+ * List&lt;T&gt; copyList(List&lt;T&gt; source) {
+ *     List&lt;T&gt; target = makeList( new TypeToken&lt;T&gt;(){} , 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());
+    }
+
+}