Przeglądaj źródła

poprawione działanie APT

MultiMap - rozszerza Map<K,Collection<V>> zamiast Map<K, List<V>>
Ranides Atterwim 13 lat temu
rodzic
commit
5a6342e040

+ 1 - 1
src/main/java/net/ranides/assira/annotations/Meta.java

@@ -208,7 +208,7 @@ public final class Meta {
     @Retention(SOURCE)
     @Documented
     @Target(TYPE)
-    public @interface ExportService {
+    public @interface JavaService {
         Class value() default void.class;
     }
 

+ 72 - 60
src/main/java/net/ranides/assira/annotations/ProcessorDef.java

@@ -12,12 +12,13 @@ import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
-import java.util.List;
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 import javax.annotation.processing.AbstractProcessor;
 import javax.annotation.processing.Filer;
 import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.DeclaredType;
@@ -28,36 +29,39 @@ import javax.lang.model.util.Elements;
 import javax.tools.Diagnostic.Kind;
 import javax.tools.FileObject;
 import javax.tools.StandardLocation;
-import net.ranides.assira.collection.SingleCollection;
 import net.ranides.assira.collection.map.MultiHashMap;
 import net.ranides.assira.collection.map.MultiMap;
+import net.ranides.assira.io.FileHelper;
 
 /**
- *
+ * 
+ * Based on "org.kohsuke.metainf-services"
+ * http://weblogs.java.net/blog/kohsuke/archive/2009/03/my_project_of_t.html 
+ * (C) by Kohsuke Kawaguchi(kk@kohsuke.org) under MIT license
+ * 
  * @author ranides
  */
+@SupportedAnnotationTypes(
+    "net.ranides.assira.annotations.Meta.JavaService"
+)
 public class ProcessorDef extends AbstractProcessor {
     
-    private static final Set<String> SUPPORTED = new SingleCollection<String>(Meta.ExportService.class.getName());
-    
-    @Override
-    public Set<String> getSupportedAnnotationTypes() {
-        return SUPPORTED;
-    }
-
     @Override
     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
-        if ( roundEnv.processingOver() ) {
-            return false;
+        if ( !roundEnv.processingOver() ) {
+            writeMeta( readMeta( getServices(roundEnv) ) );
         }
-
-        MultiMap<String, String> services = new MultiHashMap<String, String>();
+        return false;
+    }
+    
+    private MultiMap<String, String> getServices(RoundEnvironment roundEnv) {
         
+        MultiMap<String, String> services = new MultiHashMap<String, String>();
         Elements elements = processingEnv.getElementUtils();
-
+        
         // discover services from the current compilation sources
-        for (Element element : roundEnv.getElementsAnnotatedWith(Meta.ExportService.class)) {
-            Meta.ExportService info = element.getAnnotation(Meta.ExportService.class);
+        for (Element element : roundEnv.getElementsAnnotatedWith(Meta.JavaService.class)) {
+            Meta.JavaService info = element.getAnnotation(Meta.JavaService.class);
             if(info==null) {
                 continue; // shouldn't happen - ignore
             }
@@ -75,32 +79,41 @@ public class ProcessorDef extends AbstractProcessor {
             String tn = elements.getBinaryName(type).toString();
             services.putItem(cn, tn);
         }
+        return services;
+    }
 
-        // also load up any existing values, since this compilation may be partial
+    private MultiMap<String, String> readMeta(MultiMap<String, String> services) {
         Filer filer = processingEnv.getFiler();
-        for (Map.Entry<String,List<String>> e : services.entrySet()) {
+        
+        for (Map.Entry<String, Collection<String>> e : services.entrySet()) {
+            BufferedReader reader = null;
             try {
                 String contract = e.getKey();
-                List<String> target = e.getValue();
+                Collection<String> target = e.getValue();
                 
                 FileObject file = filer.getResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/services/" +contract);
-                BufferedReader reader = new BufferedReader(new InputStreamReader(file.openInputStream(), "UTF-8"));
+                reader = new BufferedReader(new InputStreamReader(file.openInputStream(), "UTF-8"));
                 String line;
                 while( null!=(line=reader.readLine()) ) { target.add(line); }
-                reader.close();
                 
-            } catch (FileNotFoundException x) {
-                // doesn't exist
-            } catch (IOException x) {
-                processingEnv.getMessager().printMessage(Kind.ERROR,"Failed to load existing service definition files: "+x);
+            } catch (FileNotFoundException _) {
+                // ignore, if doesn't exist
+            } catch (IOException cause) {
+                processingEnv.getMessager().printMessage(Kind.ERROR,"Failed to load existing service definition files: "+cause);
+            } finally {
+                FileHelper.close(reader);
             }
         }
+        return services;
+    }
+
+    private MultiMap<String, String> writeMeta(MultiMap<String, String> services) {
+        Filer filer = processingEnv.getFiler();
 
-        // now write them back out
-        for (Map.Entry<String,List<String>> e : services.entrySet()) {
+        for (Map.Entry<String,Collection<String>> e : services.entrySet()) {
             try {
                 String contract = e.getKey();
-                List<String> classes = e.getValue();
+                Collection<String> classes = e.getValue();
                 processingEnv.getMessager().printMessage(Kind.NOTE,"Writing META-INF/services/"+contract);
                 
                 FileObject file = filer.createResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/services/" +contract);
@@ -109,46 +122,45 @@ public class ProcessorDef extends AbstractProcessor {
                     writer.println(value);
                 }
                 writer.close();
-                
             } catch (IOException x) {
                 processingEnv.getMessager().printMessage(Kind.ERROR,"Failed to write service definition files: "+x);
             }
         }
-
-        return false;
+        return services;
     }
-
-    private TypeElement getContract(TypeElement type, Meta.ExportService a) {
-        // explicitly specified?
-        try {
-            a.value();
-            throw new AssertionError();
-        } catch (MirroredTypeException e) {
-            TypeMirror m = e.getTypeMirror();
-            if (m.getKind()== TypeKind.VOID) {
-                // contract inferred from the signature
-                boolean hasBaseClass = type.getSuperclass().getKind()!=TypeKind.NONE && !isObject(type.getSuperclass());
-                boolean hasInterfaces = !type.getInterfaces().isEmpty();
-                if(hasBaseClass^hasInterfaces) {
-                    if(hasBaseClass)
-                        return (TypeElement)((DeclaredType)type.getSuperclass()).asElement();
-                    return (TypeElement)((DeclaredType)type.getInterfaces().get(0)).asElement();
-                }
-
-                error(type, "Contract type was not specified, but it couldn't be inferred.");
-                return null;
+    
+    private TypeElement getContract(TypeElement type, Meta.JavaService annotation) {
+        TypeMirror m = getExportValue(annotation);
+        if (m.getKind()== TypeKind.VOID) {
+            // contract inferred from the signature
+            boolean hasBaseClass = type.getSuperclass().getKind()!=TypeKind.NONE && !isObject(type.getSuperclass());
+            boolean hasInterfaces = !type.getInterfaces().isEmpty();
+            if(hasBaseClass^hasInterfaces) {
+                if(hasBaseClass)
+                    return (TypeElement)((DeclaredType)type.getSuperclass()).asElement();
+                return (TypeElement)((DeclaredType)type.getInterfaces().get(0)).asElement();
             }
 
-            if (m instanceof DeclaredType) {
-                DeclaredType dt = (DeclaredType) m;
-                return (TypeElement)dt.asElement();
-            } else {
-                error(type, "Invalid type specified as the contract");
-                return null;
-            }
+            error(type, "Contract type was not specified, but it couldn't be inferred.");
+            return null;
         }
 
-
+        if (m instanceof DeclaredType) {
+            DeclaredType dt = (DeclaredType) m;
+            return (TypeElement)dt.asElement();
+        } else {
+            error(type, "Invalid type specified as the contract");
+            return null;
+        }
+    }
+    
+    private TypeMirror getExportValue(Meta.JavaService annotation) {
+        try {
+            annotation.value();
+            throw new AssertionError();
+        } catch (MirroredTypeException exception) {
+            return exception.getTypeMirror();
+        }
     }
 
     private boolean isObject(TypeMirror t) {

+ 45 - 18
src/main/java/net/ranides/assira/collection/map/MultiHashMap.java

@@ -9,8 +9,8 @@ package net.ranides.assira.collection.map;
 
 import java.util.Map.Entry;
 import java.util.*;
+import net.ranides.assira.collection.CollectionUtils;
 import net.ranides.assira.collection.ListUtils;
-import net.ranides.assira.collection.list.JoinList;
 
 /**
  * Implementacja interfejsu {@link MultiMap} oparta o mapę hashującą. 
@@ -18,7 +18,7 @@ import net.ranides.assira.collection.list.JoinList;
  * @param <K>
  * @param <V> 
  */
-public class MultiHashMap<K,V> extends HashMap<K, List<V>> implements MultiMap<K,V> {
+public class MultiHashMap<K,V> extends HashMap<K, Collection<V>> implements MultiMap<K,V> {
 
     private static final long serialVersionUID = 5L;
 
@@ -63,13 +63,18 @@ public class MultiHashMap<K,V> extends HashMap<K, List<V>> implements MultiMap<K
      * @param source 
      * @throws  NullPointerException if the specified map is null
      */
-    public MultiHashMap(Map<? extends K, ? extends List<V>> source) {
-        super(source);
+    public MultiHashMap(MultiMap<? extends K, ? extends V> source) {
+        super();
+        for(Entry<? extends K, ? extends Collection<? extends V>> entry : source.entrySet()) {
+            Collection<V> copy = createCollection();
+            copy.addAll(entry.getValue());
+            put(entry.getKey(), copy);
+        }
     }
     
     @Override
     public boolean containsItem(V value) {
-        for( List<V> list : values() ) {
+        for( Collection<V> list : values() ) {
             if( list.contains(value) ) { return true; }
         }
         return false;
@@ -77,23 +82,28 @@ public class MultiHashMap<K,V> extends HashMap<K, List<V>> implements MultiMap<K
 
     @Override
     public V getFirst(K key) {
-        return ListUtils.first(get(key));
+        return CollectionUtils.first(get(key));
     }
 
     @Override
     public V getLast(K key) {
-        return ListUtils.last(get(key));
+        Collection<V> elements = get(key);
+        if(elements instanceof List) {
+            return ListUtils.last((List<V>)elements);
+        } else {
+            return CollectionUtils.last(get(key));
+        }
     }
 
     @Override
     public void putItem(K key, V value) {
         if( containsKey(key) ) {
-            List<V> list = get(key);
+            Collection<V> list = get(key);
             if( !list.contains(value) ) {
                 list.add(value);
             }
         } else {
-            put(key, new LinkedList<V>() );
+            put(key, createCollection());
             get(key).add(value);
         }
     }
@@ -107,7 +117,7 @@ public class MultiHashMap<K,V> extends HashMap<K, List<V>> implements MultiMap<K
 
     @Override
     public void putItems(MultiMap<? extends K, ? extends V> source) {
-        for(Entry<? extends K, ? extends List<? extends V>> item : source.entrySet() ) {
+        for(Entry<? extends K, ? extends Collection<? extends V>> item : source.entrySet() ) {
             final K key = item.getKey();
             for(V value : item.getValue() ) {
                 putItem(key, value);
@@ -117,35 +127,52 @@ public class MultiHashMap<K,V> extends HashMap<K, List<V>> implements MultiMap<K
 
     @Override
     public V removeFirst(K key) {
-        List<V> list = get(key);
+        Collection<V> list = get(key);
         if( null == list || list.isEmpty() ) { return null; }
-        return list.remove(0);
+        Iterator<V> iterator = list.iterator();
+        V result = iterator.next();
+        iterator.remove();
+        return result;
     }
 
     @Override
     public V removeLast(K key) {
-        List<V> list = get(key);
-        if( null == list || list.isEmpty() ) { return null; }
-        return list.remove(list.size()-1);
+        Collection<V> elements = get(key);
+        if( null == elements || elements.isEmpty() ) { return null; }
+        
+        if (elements instanceof List) {
+            List<V> list = (List<V>) elements;
+            return list.remove(list.size()-1);
+        } else {
+            Iterator<V> iterator = elements.iterator();
+            V result = null;
+            while(iterator.hasNext()) { result = iterator.next(); }
+            iterator.remove();
+            return result;
+        }
     }
 
     @Override
     public boolean removeItem(K key, V value) {
-        List<V> list = get(key);
+        Collection<V> list = get(key);
         if( null == list || list.isEmpty() ) { return false; }
         return list.remove(value);
     }
 
     @Override
     public List<V> items() {
-        return new JoinList<V>();
+        throw new UnsupportedOperationException("Not supported yet.");
     }
     
     @Override
     public int multiSize() {
         int result = 0;
-        for(List<V> list : values()) { result+= list.size(); }
+        for(Collection<V> list : values()) { result+= list.size(); }
         return result;
     }
 
+    protected Collection<V> createCollection() {
+        return new HashSet<V>();
+    }
+    
 }

+ 1 - 1
src/main/java/net/ranides/assira/collection/map/MultiMap.java

@@ -22,7 +22,7 @@ import java.util.*;
  *      - HashMap<List<V>>
  *      - HashMap<LinkedHashSet<V>>
  */
-public interface MultiMap<K,V> extends Map<K, List<V>> {
+public interface MultiMap<K,V> extends Map<K, Collection<V>> {
         
     /**
      * Sprawdza, czy podana wartość została conajmniej raz przypisana 

+ 12 - 6
src/main/java/net/ranides/assira/events/NamedEventListener.java

@@ -7,8 +7,9 @@
 package net.ranides.assira.events;
 
 import java.lang.reflect.Method;
+import java.util.Collection;
 import java.util.Iterator;
-import java.util.List;
+import java.util.LinkedList;
 import net.ranides.assira.annotations.Meta;
 import net.ranides.assira.collection.map.MultiHashMap;
 import net.ranides.assira.collection.map.MultiMap;
@@ -44,7 +45,12 @@ public class NamedEventListener implements Observable {
     
     private static final String GLOBAL = "global://*";
     
-    private final MultiMap<String, EventListener<? super Event>> listeners = new MultiHashMap<String, EventListener<? super Event>>();
+    private final MultiMap<String, EventListener<? super Event>> listeners = new MultiHashMap<String, EventListener<? super Event>>(){
+        @Override
+        protected Collection<EventListener<? super Event>> createCollection() {
+            return new LinkedList<EventListener<? super Event>>();
+        }
+    };
 
     /**
      * {@code NamedEventListener} nie może tworzony bez pośrednio - można jedynie
@@ -104,7 +110,7 @@ public class NamedEventListener implements Observable {
         return true;
     }
     
-    private void runBindings(List<EventListener<? super Event>> list, NamedEvent event) {
+    private void runBindings(Collection<EventListener<? super Event>> list, NamedEvent event) {
         if(list == null) {
             return;
         }
@@ -171,7 +177,7 @@ public class NamedEventListener implements Observable {
      */
     @Override
     public final synchronized void removeAllEventListeners() {
-        for(List<EventListener<? super Event>> list : listeners.values()) {
+        for(Collection<EventListener<? super Event>> list : listeners.values()) {
             Iterator<EventListener<? super Event>> iterator = list.iterator();
             while(iterator.hasNext()) {
                 EventListener<? super Event> value = iterator.next();
@@ -180,9 +186,9 @@ public class NamedEventListener implements Observable {
                 }
             }
         }
-        Iterator<List<EventListener<? super Event>>> iterator = listeners.values().iterator();
+        Iterator<Collection<EventListener<? super Event>>> iterator = listeners.values().iterator();
         while(iterator.hasNext()) {
-            List<EventListener<? super Event>> value = iterator.next();
+            Collection<EventListener<? super Event>> value = iterator.next();
             if(value.isEmpty()) {
                 iterator.remove();
             }