Quellcode durchsuchen

fix: TypeToken (parameter resolution)
fix: IClass#raw - doesn't throw for wildcards
new: IMethod#handle(interface)
new: IMethod#functor(interface)

Ranides Atterwim vor 9 Jahren
Ursprung
Commit
ba8e4e1d46

+ 6 - 2
assira/src/main/java/net/ranides/assira/generic/TypeToken.java

@@ -6,6 +6,7 @@
  */
 package net.ranides.assira.generic;
 
+import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.List;
 import java.util.Set;
@@ -70,10 +71,13 @@ public abstract class TypeToken<T> extends AClass<T> {
      *
      */
     protected TypeToken() {
-        this.type = IClass.typeinfo(getClass()).params().get(0);
+        // typeinfo(class).params[0]
+        // wstawiło by nam do kontekstu parametr "T" pobrany z deklaracji TypeTokena
+        ParameterizedType ptype = (ParameterizedType)getClass().getGenericSuperclass();
+        this.type = IClass.typeinfo(ptype.getActualTypeArguments()[0]);
     }
 	
-	protected TypeToken(Class<?> type) {
+	protected TypeToken(Type type) {
 		this.type = IClass.typeinfo(type);
 	}
     

+ 119 - 0
assira/src/main/java/net/ranides/assira/io/uri/URIBuilder.java

@@ -0,0 +1,119 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.io.uri;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public class URIBuilder {
+    
+    // @todo (assira #2) URIBuilder
+    
+    public static URIBuilder from(String value) {
+        return new URIBuilder();
+    }
+    
+    public static URIBuilder from(URI value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+    public static URIBuilder from(URL value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+    public String login() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+    public URIBuilder login(String value) {
+        return this;
+    }
+    
+    public String password() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+    public URIBuilder password(String value) {
+        return this;
+    }
+    
+    public String host() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+    public URIBuilder host(String value) {
+        return this;
+    }
+    
+    public Optional<String> fragment() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+    public URIBuilder fragment(String value) {
+        return this;
+    }
+    
+    public String path() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+    public URIBuilder path(String value) {
+        return this;
+    }
+    
+    public URIBuilder path(String... values) {
+        return this;
+    }
+    
+    public Optional<Integer> port() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+    public URIBuilder port(String value) {
+        return this;
+    }
+    
+    public URIBuilder port(int value) {
+        return this;
+    }
+    
+    public List<String> param(String name) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+    public URIBuilder param(String name, String value) {
+        return this;
+    }
+    
+    public Map<String,String> params() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+    public URIBuilder params(Map<String,String> value) {
+        return this;
+    }
+    
+    public URIBuilder scheme(String value) {
+        return this;
+    }
+    
+    public URIBuilder resolve(Object context) {
+        return this;
+    }
+    
+    public URI build() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+}

+ 5 - 1
assira/src/main/java/net/ranides/assira/reflection/IMethod.java

@@ -104,5 +104,9 @@ public interface IMethod extends IElement {
     Method reflective();
     
     MethodHandle handle();
-
+    
+    <F> F functor(IClass<F> functor);
+    
+    MethodHandle handle(IClass<?> functor);
+    
 }

+ 44 - 0
assira/src/main/java/net/ranides/assira/reflection/impl/AMethod.java

@@ -8,12 +8,19 @@
 package net.ranides.assira.reflection.impl;
 
 import java.lang.annotation.Annotation;
+import java.lang.invoke.CallSite;
+import java.lang.invoke.LambdaConversionException;
+import java.lang.invoke.LambdaMetafactory;
 import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleProxies;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 import net.ranides.assira.reflection.*;
 import net.ranides.assira.text.StrBuilder;
 import net.ranides.assira.trace.ExceptionUtils;
 import net.ranides.assira.collection.query.CQueryBuilder;
 import net.ranides.assira.functional.VarFunction;
+import static net.ranides.assira.reflection.IAttribute.*;
 
 /**
  *
@@ -78,7 +85,44 @@ public abstract class AMethod implements IMethod {
             }
         };
 	}
+
+    @Override
+    public <F> F functor(IClass<F> functor) {
+        return (F)MethodHandleProxies.asInterfaceInstance(functor.raw(), handle());
+    }
+
+    @Override
+    public MethodHandle handle(IClass<?> functor) {
+        try {
+            Class<?> rfunctor = functor.raw();
+            
+            IMethod method = IClass.typeinfo(rfunctor).methods().require(DECLARED).discard(SYNTHETIC).discard(BRIDGE).first();
+        
+            return site(method, functor.raw()).getTarget();
+            
+        } catch(LambdaConversionException cause) {
+            throw ExceptionUtils.rethrow(cause);
+        }
+    }
     
+    private CallSite site(IMethod method, Class<?> functor) throws LambdaConversionException {
+        MethodHandle handle = handle();
+        
+        MethodType signature = MethodType.methodType(
+            method.returns().raw(), 
+            method.arguments().types().raw().array(Class[]::new)
+        );
+        
+        return LambdaMetafactory.metafactory(
+            MethodHandles.lookup(), 
+            method.name(), 
+            MethodType.methodType(functor), 
+            signature, 
+            handle, 
+            handle.type()
+        );
+    }
+  
     @Override
     public final int hashCode() {
         return name().hashCode();

+ 1 - 1
assira/src/main/java/net/ranides/assira/reflection/impl/AMethods.java

@@ -163,7 +163,7 @@ public class AMethods extends AElements<IMethod> implements IMethods {
 
     @Override
     public CQuery<MethodHandle> handle() {
-        return stream().map(IMethod::handle);
+        return stream().map(m -> m.handle());
     }
 
     

+ 1 - 1
assira/src/main/java/net/ranides/assira/reflection/impl/RWClass.java

@@ -96,7 +96,7 @@ public class RWClass<T> extends AClass<T> {
 
     @Override
     public Class<?> raw() {
-        throw new UnsupportedOperationException("IClass<Wildcard> is not reflective");
+        return Object.class;
     }
 
     @Override

+ 12 - 0
assira/src/test/java/net/ranides/assira/generic/TypeTokenTest.java

@@ -10,6 +10,7 @@ import java.util.List;
 import org.junit.Test;
 import static net.ranides.assira.junit.NewAssert.*;
 import net.ranides.assira.reflection.IClass;
+import net.ranides.assira.reflection.mockup.MTFunction;
 
 /**
  *
@@ -38,6 +39,17 @@ public class TypeTokenTest {
         assertEquals(List.class, c5.raw());
     }
     
+    @Test
+    public void testTokenRaw() {
+        IClass<?> c1 = new TypeToken<MTFunction<String>>(){};
+        IClass<?> c2 = new TypeToken<MTFunction<?>>(){};
+        IClass<?> c3 = new TypeToken<MTFunction>(){};
+
+        assertEquals("net.ranides.assira.reflection.mockup.MTFunction<java.lang.String>", c1.toString());
+        assertEquals("net.ranides.assira.reflection.mockup.MTFunction<?>", c2.toString());
+        assertEquals("net.ranides.assira.reflection.mockup.MTFunction<T>", c3.toString());
+    }
+    
     @Test
     @SuppressWarnings("unchecked")
     public void testEquals() {

+ 46 - 5
assira/src/test/java/net/ranides/assira/reflection/IMethodTest.java

@@ -6,9 +6,7 @@
  */
 package net.ranides.assira.reflection;
 
-import java.lang.annotation.Annotation;
 import java.util.Arrays;
-import java.util.List;
 import java.util.Set;
 import java.util.function.BiFunction;
 import java.util.function.Function;
@@ -17,8 +15,8 @@ import static net.ranides.assira.reflection.IAttribute.*;
 import static net.ranides.assira.reflection.mockup.ForIClass.*;
 import org.junit.Test;
 import static net.ranides.assira.junit.NewAssert.*;
-import net.ranides.assira.reflection.impl.CPInspector;
-import org.junit.Ignore;
+import net.ranides.assira.reflection.mockup.MTFunction;
+import net.ranides.assira.reflection.mockup.MTFunction.MTRecord;
 
 /**
  *
@@ -93,7 +91,7 @@ public class IMethodTest {
     }
     
     @Test
-    public void testFunctor() {
+    public void testFromFunctor() {
         int value1 = 1;
 		int[] array2 = new int[]{1,2,3,4,5};
         @SuppressWarnings("Convert2Lambda")
@@ -179,6 +177,49 @@ public class IMethodTest {
         
     }
     
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testToHandle() throws Throwable {
+        
+        Object that = new MTRecord(300);
+        IMethod m1 = IClass.typefor(that).method("sum");
+        IMethod m2 = IClass.typefor(that).method("mul");
+        
+        MTFunction<MTRecord> f11 = (MTFunction<MTRecord>)m1.handle(MTFunction.GENERIC).invokeExact();
+        MTFunction<MTRecord> f12 = (MTFunction)m1.handle(MTFunction.RAW).invokeExact();
+        
+        assertEquals(107, f11.calculate(new MTRecord(100), 3, 4));
+        assertEquals(208, f12.calculate(new MTRecord(200), 3, 5));
+        
+        MTFunction<MTRecord> f21 = (MTFunction<MTRecord>)m2.handle(MTFunction.GENERIC).invokeExact();
+        MTFunction<MTRecord> f22 = (MTFunction)m2.handle(MTFunction.RAW).invokeExact();
+        
+        assertEquals(112, f21.calculate(new MTRecord(100), 3, 4));
+        assertEquals(215, f22.calculate(new MTRecord(200), 3, 5));
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testToFunctor() throws Throwable {
+        
+        Object that = new MTRecord(300);
+        IMethod m1 = IClass.typefor(that).method("sum");
+        IMethod m2 = IClass.typefor(that).method("mul");
+        
+        MTFunction<MTRecord> f11 = m1.functor(MTFunction.GENERIC);
+        MTFunction<MTRecord> f12 = m1.functor(MTFunction.RAW);
+        
+        assertEquals(309, f11.calculate(new MTRecord(300), 3, 6));
+        assertEquals(410, f12.calculate(new MTRecord(400), 3, 7));
+        
+        MTFunction<MTRecord> f21 = m2.functor(MTFunction.GENERIC);
+        MTFunction<MTRecord> f22 = m2.functor(MTFunction.RAW);
+        
+        assertEquals(318, f21.calculate(new MTRecord(300), 3, 6));
+        assertEquals(421, f22.calculate(new MTRecord(400), 3, 7));
+    }
+    
     private void testAPI(Set<IAttribute> exp, Object function1, Object function2, Object function3, Object function4, Object function5) {
         IMethod m1 = IMethod.function(function1);
 		IMethod m2 = IMethod.function(function2);

+ 3 - 6
assira/src/test/java/net/ranides/assira/reflection/impl/RWClassTest.java

@@ -31,9 +31,7 @@ public class RWClassTest {
         assertEquals("[java.lang.Object]", ic1.parents().toString());
         assertEquals(Arrays.asList(), ic1.interfaces().stream().distinct().list());
         assertEquals("? super java.util.ArrayList<java.lang.Float>", ic1.reflective().toString());
-        assertThrows(UnsupportedOperationException.class, ()->{
-            ic1.raw();
-        });
+        assertEquals(Object.class, ic1.raw());
         // @todo (assira #6) reflective: generics: isInstance dla wildcards
         // rzecz w tym, że my tu mamy unresolved params, bo przekazujemy objekt (i type erasure wchodzi)
         // a to oznacza, że NIE powinno tutaj nic matchować na ten moment
@@ -65,9 +63,8 @@ public class RWClassTest {
         );
         assertEquivalent(interfaces2, ic2.interfaces().stream().distinct().map(c -> c.toString()).list());
         assertEquals("? extends java.util.ArrayList<java.lang.Float>", ic2.reflective().toString());
-        assertThrows(UnsupportedOperationException.class, ()->{
-            ic2.raw();
-        });
+        assertEquals(Object.class, ic2.raw());
+        
 //        assertEquals(false, ic2.isInstance(new ArrayList<Float>()));        // ?
 //        assertEquals(false, ic2.isInstance(new ArrayList<Double>()));       // ?
 //        assertEquals(false, ic2.isInstance(new LinkedList<Float>()));       // ?

+ 41 - 0
assira/src/test/java/net/ranides/assira/reflection/mockup/MTFunction.java

@@ -0,0 +1,41 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.reflection.mockup;
+
+import net.ranides.assira.generic.TypeToken;
+import net.ranides.assira.reflection.IClass;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public interface MTFunction<T> {
+    
+    IClass<MTFunction<MTRecord>> GENERIC = new TypeToken<MTFunction<MTRecord>>(){};
+    
+    IClass<MTFunction> RAW = new TypeToken<MTFunction>(){};
+    
+    int calculate(T action, int a, int b);
+    
+    class MTRecord {
+        
+        private final int seed;
+
+        public MTRecord(int seed) {
+            this.seed = seed;
+        }
+        
+        public int sum(int a, int b) {
+            return seed+a+b;
+        }
+        
+        public int mul(int a, int b) {
+            return seed+a*b;
+        }
+        
+    };
+}