Ranides Atterwim 10 лет назад
Родитель
Сommit
b8b0d665f5

+ 81 - 8
assira/src/main/java/net/ranides/assira/reflection/impl/RCompareUtils.java

@@ -70,25 +70,98 @@ public final class RCompareUtils {
         }
         }
         Bound sw = new Bound(isuper);
         Bound sw = new Bound(isuper);
         Bound cw = new Bound(iclass);
         Bound cw = new Bound(iclass);
+        List<IClass> sp = isuper.params();
+        List<IClass> cp = iclass.params();
+        
         if(sw.wildcard || cw.wildcard) {
         if(sw.wildcard || cw.wildcard) {
-            return isSuperBound(sw, cw);
+            return isSuperBound(sw, cw) && matchParams(isuper, iclass);
         }
         }
         Class<?> sr = isuper.reflective();
         Class<?> sr = isuper.reflective();
         Class<?> cr = iclass.reflective();
         Class<?> cr = iclass.reflective();
-        List<IClass> sp = isuper.params();
-        List<IClass> cp = iclass.params();
-        return isSuperRaw(box, sr, cr) && sp.equals(cp);
+        
+        return isSuperRaw(box, sr, cr) && matchParams(isuper, iclass);
     }
     }
     
     
     private static boolean isSuperRaw(boolean box, Class<?> isuper, Class<?> iclass) {
     private static boolean isSuperRaw(boolean box, Class<?> isuper, Class<?> iclass) {
         return box ? ClassTraits.isSuper(isuper, iclass) : isuper.isAssignableFrom(iclass);
         return box ? ClassTraits.isSuper(isuper, iclass) : isuper.isAssignableFrom(iclass);
     }
     }
-
     
     
     private static boolean isSuperBound(Bound isuper, Bound iclass) {
     private static boolean isSuperBound(Bound isuper, Bound iclass) {
-        // @todo (assira #0) reflective wildcards issuper
-        throw new UnsupportedOperationException("Not supported yet.");
-//        return isuper.params().equals(iclass.params());
+        if(isuper.lower.length > 0) {
+            for(IClass sc : isuper.lower) {
+                if( isanysubclass(sc, iclass.upper) ) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        if(iclass.lower.length > 0) {
+            return isallobject(isuper.upper);
+        }
+        if( !isuper.wildcard ) {
+            return isanysubclass(isuper.upper[0], iclass.upper);
+        }
+        for(IClass ec : isuper.upper) {
+            if( !isanysubclass(ec, iclass.lower)) {
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    private static boolean match(IClass isuper, IClass iclass) {
+        Bound sw = new Bound(isuper);
+        Bound cw = new Bound(iclass);
+        if(sw.wildcard || cw.wildcard) {
+            return matchBound(sw, cw);
+        }
+        Class<?> sr = isuper.reflective();
+        Class<?> cr = iclass.reflective();
+        return matchRaw(sr, cr) && matchParams(isuper, iclass);
+    }
+    
+    private static boolean matchBound(Bound isuper, Bound iclass) {
+        if(isuper.lower.length > 0) {
+            if(iclass.wildcard) {
+                return (iclass.lower.length > 0) && isSuper(iclass.lower[0], isuper.lower[0]);
+            } 
+            return isSuper(iclass.upper[0], isuper.lower[0]);
+        }
+        if(!isuper.wildcard) {
+            return !iclass.wildcard && equals(isuper.upper[0], iclass.upper[0]);
+        }
+        for(IClass sc : isuper.upper) {
+            if( !isanysubclass(sc, iclass.upper) ) {
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    private static boolean matchRaw(Class<?> isuper, Class<?> iclass) {
+        return isuper.isAssignableFrom(iclass);
+    }
+    
+    private static boolean matchParams(IClass isuper, IClass iclass) {
+        return ListUtils.equals(isuper.params(), iclass.params(), RCompareUtils::match);
+    }
+    
+    private static boolean isanysubclass(IClass isuper, IClass[] list) {
+        for(IClass s : list) {
+            if( isSubclass(s, isuper)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    private static boolean isallobject(IClass[] list) {
+        for(IClass s : list) {
+            if( !RClass.OBJECT.equals(s) ) {
+                return false;
+            }
+        }
+        return true;
     }
     }
     
     
     private static class Bound {
     private static class Bound {

+ 91 - 93
assira/src/test/java/net/ranides/assira/reflection/impl/RCompareUtilsTest.java

@@ -10,6 +10,8 @@ import net.ranides.assira.reflection.IClass;
 import net.ranides.assira.reflection.mockup.ForRCompareUtils;
 import net.ranides.assira.reflection.mockup.ForRCompareUtils;
 import org.junit.Test;
 import org.junit.Test;
 import org.junit.Ignore;
 import org.junit.Ignore;
+import static net.ranides.assira.junit.NewAssert.*;
+
 
 
 /**
 /**
  *
  *
@@ -17,120 +19,116 @@ import org.junit.Ignore;
  */
  */
 public class RCompareUtilsTest {
 public class RCompareUtilsTest {
     
     
-    public RCompareUtilsTest() {
-    }
-
-    @Ignore
+    // Dobra. Zaimplementowaliśmy coś, co się zgadza na poziomie basic z JAVAC.
+    // Czy się zgadza w 100% to nie wiadomo. Ale też nas to nic nie obchodzi tak naprawdę na ten moment.
+    // Co jest bardzo dobrą wiadomością, to że tabelka wartości jest transpozycją po zmianie kolejności parametrów,
+    // czyli jakieś elementarne własności funkcji porządkującej to mamy.
+    
     @Test
     @Test
-    public void testWildcards() {
-        
-        ForRCompareUtils u = new ForRCompareUtils();
-        
-        IClass ic = IClass.typeinfo(ForRCompareUtils.class);
-        IClass supA = ic.fields().require("superA").first().get().type();
-        IClass clsA = ic.fields().require("classA").first().get().type();
-        IClass extA = ic.fields().require("extenA").first().get().type();
-        
-//        System.out.printf("%s%n", RCompareUtils. clsA.params().get(0).getClass());
-        
-        System.out.printf("type = %s%n", supA.isSubclass(supA) );
-        System.out.printf("type = %s%n", supA.isSubclass(clsA) );
-        System.out.printf("type = %s%n", supA.isSubclass(extA) );
-        System.out.printf("%n");
-        System.out.printf("type = %s%n", clsA.isSubclass(supA) );
-        System.out.printf("type = %s%n", clsA.isSubclass(clsA) );
-        System.out.printf("type = %s%n", clsA.isSubclass(extA) );
-        System.out.printf("%n");
-        System.out.printf("type = %s%n", extA.isSubclass(supA) );
-        System.out.printf("type = %s%n", extA.isSubclass(clsA) );
-        System.out.printf("type = %s%n", extA.isSubclass(extA) );
-        
-        
+    public void testWildcardsDirect() {
         /*
         /*
-             | sup | cls | ext      assign list
+             | sup | cls | ext      JDK / type
         -----+-----+-----+-----
         -----+-----+-----+-----
-         sup |  +  |  -  |  -
-         cls |  +  |  +  |  +
-         ext |  -  |  -  |  +
-        
+         sup |     |     |   
+         cls |  +  |  +  |   
+         ext |  +  |  +  |   
+       
+             | sup | cls | ext      issuper / type
+        -----+-----+-----+-----
+         sup |     |     |   
+         cls |  +  |  +  |   
+         ext |  +  |  +  |   
         
         
-             | sup | cls | ext      list.add
+             | sup | cls | ext      issublcass / type
         -----+-----+-----+-----
         -----+-----+-----+-----
-         sup |  -  |  -  |  -
-         cls |  +  |  +  |  -
-         ext |  +  |  +  |  -
+         sup |     |  +  |  +
+         cls |     |  +  |  +
+         ext |     |     |   
+        */
+        IClass ic = IClass.typeinfo(ForRCompareUtils.class);
+        IClass supA = ic.fields().require("superA").first().get().type().params().get(0);
+        IClass clsA = ic.fields().require("classA").first().get().type().params().get(0);
+        IClass extA = ic.fields().require("extenA").first().get().type().params().get(0);
         
         
+        assertFalse( supA.isSuper(supA) );
+        assertTrue( supA.isSuper(clsA) );
+        assertTrue( supA.isSuper(extA) );
+
+        assertFalse( clsA.isSuper(supA) );
+        assertTrue( clsA.isSuper(clsA) );
+        assertTrue( clsA.isSuper(extA) );
         
         
-             | sup | cls | ext      issuper
-        -----+-----+-----+-----
-         sup |  -  |  -  |  +
-         cls |  -  |  +  |  +
-         ext |  +  |  +  |  +
+        assertFalse( extA.isSuper(supA) );
+        assertFalse( extA.isSuper(clsA) );
+        assertFalse( extA.isSuper(extA) );
         
         
-             | sup | cls | ext      issuper (2)
-        -----+-----+-----+-----
-         sup |  +  |  +  |  +
-         cls |  -  |  -  |  -
-         ext |  -  |  -  |  -
+        // ---
         
         
+        assertFalse( supA.isSubclass(supA) );
+        assertFalse( supA.isSubclass(clsA) );
+        assertFalse( supA.isSubclass(extA) );
+
+        assertTrue( clsA.isSubclass(supA) );
+        assertTrue( clsA.isSubclass(clsA) );
+        assertFalse( clsA.isSubclass(extA) );
         
         
-             | sup | cls | ext      issubclass
+        assertTrue( extA.isSubclass(supA) );
+        assertTrue( extA.isSubclass(clsA) );
+        assertFalse( extA.isSubclass(extA) );
+    }
+
+    @Test
+    public void testWildcards() {
+        /*
+             | sup | cls | ext      JDK / parameterized type
         -----+-----+-----+-----
         -----+-----+-----+-----
-         sup |  -  |  -  |  +
-         cls |  -  |  +  |  +
-         ext |  +  |  +  |  +
+         sup |  +  |     |   
+         cls |  +  |  +  |  +
+         ext |     |     |  +
         
         
-             | sup | cls | ext      issubclass (2)
+             | sup | cls | ext      issuper / parameterized type
         -----+-----+-----+-----
         -----+-----+-----+-----
-         sup |  +  |  -  |  -
-         cls |  -  |  -  |  -
-         ext |  -  |  -  |  -
+         sup |  +  |     |   
+         cls |  +  |  +  |  +
+         ext |     |     |  +
         
         
-        // @todo (assira #0) reflective compare
+             | sup | cls | ext      issubclass / parameterized type
+        -----+-----+-----+-----
+         sup |  +  |  +  |   
+         cls |     |  +  |   
+         ext |     |  +  |  +
+        */
         
         
-        Dobra. Zaimplementowaliśmy istotnie coś, co chcielśmy.
-        Ale nie ma to żadnego związku z zachowaniem JVM które
-        jest znacznie bardziej "subtle". 
-        Trzeba po prostu doczytać jak to działa. 
+        IClass ic = IClass.typeinfo(ForRCompareUtils.class);
+        IClass supA = ic.fields().require("superA").first().get().type();
+        IClass clsA = ic.fields().require("classA").first().get().type();
+        IClass extA = ic.fields().require("extenA").first().get().type();
         
         
-        Na dodatek chyba nie do końca sprawę przemyśleliśmy jednak
-        z tym "odwracaniem" super/subclass ponieważ w przypadku wildcardów
-        to wyszło na jedno. Albo idea jest niedobra, albo wildcardowe
-        porównania nieprawidłowe - tzn zaimplementowane tak, że są symmetric.
+        assertTrue( supA.isSuper(supA) );
+        assertTrue( supA.isSuper(clsA) );
+        assertFalse( supA.isSuper(extA) );
+
+        assertFalse( clsA.isSuper(supA) );
+        assertTrue( clsA.isSuper(clsA) );
+        assertFalse( clsA.isSuper(extA) );
         
         
-        Nie ma to w praktyce aż tak wysokiego priorytetu bo "jakoś" to to będzie
-        działać w większości "non-wildcard-owych" przypadków.
+        assertFalse( extA.isSuper(supA) );
+        assertTrue( extA.isSuper(clsA) );
+        assertTrue( extA.isSuper(extA) );
         
         
-        */
+        // -- 
         
         
+        assertTrue( supA.isSubclass(supA) );
+        assertFalse( supA.isSubclass(clsA) );
+        assertFalse( supA.isSubclass(extA) );
 
 
-    //<editor-fold defaultstate="collapsed" desc="comment">
-//        u.superA = u.superA;    // +
-//        u.superA = u.classA;    // +
-//        u.superA = u.extenA;    // -
-//
-//        u.classA = u.superA;    // -
-//        u.classA = u.classA;    // +
-//        u.classA = u.extenA;    // -
-//
-//        u.extenA = u.superA;    // -
-//        u.extenA = u.classA;    // +
-//        u.extenA = u.extenA;    // +
-    //</editor-fold>
+        assertTrue( clsA.isSubclass(supA) );
+        assertTrue( clsA.isSubclass(clsA) );
+        assertTrue( clsA.isSubclass(extA) );
         
         
-    //<editor-fold defaultstate="collapsed" desc="comment">
-//        u.superA.add(u.superA.get(0));
-//        u.superA.add(u.classA.get(0));
-//        u.superA.add(u.extenA.get(0));
-//
-//        u.classA.add(u.superA.get(0));
-//        u.classA.add(u.classA.get(0));
-//        u.classA.add(u.extenA.get(0));
-//
-//        u.extenA.add(u.superA.get(0));
-//        u.extenA.add(u.classA.get(0));
-//        u.extenA.add(u.extenA.get(0));
-    //</editor-fold>
+        assertFalse( extA.isSubclass(supA) );
+        assertFalse( extA.isSubclass(clsA) );
+        assertTrue( extA.isSubclass(extA) );
         
         
     }
     }