Explorar o código

new: AsmMethodBuilder#push(IClass)
new: Adapter: serialization
new: IClassLoader,AdapterFactory: named classloader

Mariusz Sieroń %!s(int64=6) %!d(string=hai) anos
pai
achega
ef71c5d477

+ 18 - 5
assira/src/main/java/net/ranides/assira/reflection/AdapterFactory.java

@@ -5,26 +5,39 @@ import net.ranides.assira.generic.Tuple;
 import net.ranides.assira.reflection.impl.CGAdapter;
 
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
 
 public class AdapterFactory {
 
+    private static final AdapterFactory SYSTEM = new AdapterFactory(IClassLoader.getSystem());
+
+    private static final Map<String, AdapterFactory> FACTORIES = new ConcurrentHashMap<>();
+
     private final IClassLoader loader;
 
     private final Map<Tuple, IClass<?>> GENERATED = new HashMap<>();
 
-    private static final class Li {
+    static {
 
-        public static final AdapterFactory SYSTEM = new AdapterFactory(IClassLoader.system());
+        FACTORIES.put(SYSTEM.loader().name(), SYSTEM);
 
     }
 
-    public AdapterFactory(IClassLoader loader) {
+    private AdapterFactory(IClassLoader loader) {
         this.loader = loader;
     }
 
-    public static AdapterFactory system() {
-        return Li.SYSTEM;
+    public static AdapterFactory getSystem() {
+        return SYSTEM;
+    }
+
+    public static AdapterFactory getInstance(IClassLoader loader) {
+        return FACTORIES.computeIfAbsent(loader.name(), k -> new AdapterFactory(loader));
+    }
+
+    public static AdapterFactory getInstance(String name) {
+        return getInstance(IClassLoader.getInstance(name));
     }
 
     public IClassLoader loader() {

+ 47 - 7
assira/src/main/java/net/ranides/assira/reflection/IClassLoader.java

@@ -1,17 +1,57 @@
 package net.ranides.assira.reflection;
 
-import net.ranides.assira.reflection.impl.CGLoader;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentHashMap;
 
-public interface IClassLoader {
+public class IClassLoader extends ClassLoader {
 
-    IClass<?> defineClass(String name, byte[] bytecode);
+    private static final Map<String, IClassLoader> LOADERS = new ConcurrentHashMap<>();
 
-    static IClassLoader system() {
-        return CGLoader.system();
+    private static final IClassLoader SYSTEM = new IClassLoader("system");
+
+    private final String name;
+
+    static {
+        LOADERS.put(SYSTEM.name(), SYSTEM);
+    }
+
+    private IClassLoader(String name) {
+        super();
+        this.name = name;
+    }
+
+    private IClassLoader(String name, ClassLoader parent) {
+        super(parent);
+        this.name = name;
+    }
+
+    public static IClassLoader getSystem() {
+        return SYSTEM;
+    }
+
+    public static IClassLoader getInstance(String name, ClassLoader parent) {
+        return LOADERS.computeIfAbsent(name, k -> new IClassLoader(name, parent));
+    }
+
+    public static IClassLoader getInstance(String name) {
+        IClassLoader ic = LOADERS.get(name);
+        if(ic == null) {
+            throw new NoSuchElementException("ClassLoader not found: " + name);
+        }
+        return ic;
+    }
+
+    public static void free(String name) {
+        LOADERS.remove(name);
+    }
+
+    public String name() {
+        return name;
     }
 
-    static IClassLoader loader(ClassLoader parent) {
-        return new CGLoader(parent);
+    public IClass<?> defineClass(String name, byte[] bytecode) {
+        return IClass.typeinfo(defineClass(name, bytecode, 0, bytecode.length));
     }
 
 }

+ 11 - 4
assira/src/main/java/net/ranides/assira/reflection/asm/AsmMethodBuilder.java

@@ -73,6 +73,9 @@ public class AsmMethodBuilder {
         if(null == value) {
             return ins(ACONST_NULL);
         }
+        if(value instanceof IClass) {
+            return ldc(Type.getType(((IClass)value).raw()));
+        }
         if(IClass.DOUBLE.isEquivalent(type)) {
             return pushDouble(((Number)value).doubleValue());
         }
@@ -91,7 +94,7 @@ public class AsmMethodBuilder {
         return ldc(value);
     }
 
-    public AsmMethodBuilder pushDouble(Number value) {
+    private AsmMethodBuilder pushDouble(Number value) {
         if(value.doubleValue() == 0.0) {
             return ins(DCONST_0);
         }
@@ -101,7 +104,7 @@ public class AsmMethodBuilder {
         return ldc(value.doubleValue());
     }
 
-    public AsmMethodBuilder pushFloat(Number value) {
+    private AsmMethodBuilder pushFloat(Number value) {
         if(value.floatValue() == 0.0) {
             return ins(FCONST_0);
         }
@@ -114,7 +117,7 @@ public class AsmMethodBuilder {
         return ldc(value.floatValue());
     }
 
-    public AsmMethodBuilder pushLong(long value) {
+    private AsmMethodBuilder pushLong(long value) {
         if(value == 0) {
             return ins(LCONST_0);
         }
@@ -124,7 +127,7 @@ public class AsmMethodBuilder {
         return ldc(value);
     }
 
-    public AsmMethodBuilder pushInt(Number value) {
+    private AsmMethodBuilder pushInt(Number value) {
         switch (value.intValue()) {
             case -1:
                 return ins(ICONST_M1);
@@ -227,6 +230,10 @@ public class AsmMethodBuilder {
         return this;
     }
 
+    public AsmMethodBuilder invokeInit(IConstructor<?> constructor) {
+        return invokeInit(constructor.parent(), constructor.arguments().types());
+    }
+
     public AsmMethodBuilder invokeInit(IClass<?> owner, Iterable<IClass<?>> params) {
         mv.visitMethodInsn(INVOKESPECIAL, AsmSupport.path(owner), "<init>", AsmSupport.vm(params, IClass.VOID), owner.attributes().has(IAttribute.INTERFACE));
         return this;

+ 34 - 3
assira/src/main/java/net/ranides/assira/reflection/impl/CGAdapter.java

@@ -4,9 +4,14 @@ import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
 import net.ranides.assira.annotations.Meta;
 import net.ranides.assira.reflection.*;
-import net.ranides.assira.reflection.asm.*;
-
-import java.util.*;
+import net.ranides.assira.reflection.asm.AsmClassBuilder;
+import net.ranides.assira.reflection.asm.AsmMethodBuilder;
+import net.ranides.assira.reflection.asm.AsmSupport;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.function.Function;
 
 @Slf4j
@@ -71,6 +76,8 @@ public class CGAdapter {
 
         implementToString();
 
+        implementWriteReplace();
+
         for(IMethod m : adapter.methods()) {
             new MethodLink(m).link();
         }
@@ -160,6 +167,30 @@ public class CGAdapter {
         m.end();
     }
 
+    private void implementWriteReplace() {
+        /// Object writeReplace() {
+        ///     return new GCAdapterSForm("loader-name", targetInterface, that);
+        /// }
+
+        IClass<GCAdapterSForm> sform = IClass.typeinfo(GCAdapterSForm.class);
+        IConstructor<GCAdapterSForm> sformNew = sform.constructors().first().get();
+
+        AsmMethodBuilder m = writer.method(IAttributes.of(IAttribute.PRIVATE), "writeReplace", Collections.emptyList(), IClass.OBJECT, Collections.emptyList());
+
+        m.newObject(sform);
+        m.dup();
+        m.push(factory.loader().name());
+        m.push(adapter);
+
+        m.load(IClass.OBJECT, 0);
+        m.getField(writer.type(), that, F_THAT);
+        m.invokeInit(sformNew);
+
+        m.returns(IClass.OBJECT);
+
+        m.end();
+    }
+
     private void implementInterface() {
         /// public Object net_ranides_assira_cg_that() {
         ///     return this.that;

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

@@ -1,6 +1,8 @@
 package net.ranides.assira.reflection.impl;
 
-public interface CGAdapterWrapper {
+import java.io.Serializable;
+
+public interface CGAdapterWrapper extends Serializable {
 
     Object net_ranides_assira_cg_that();
 

+ 0 - 31
assira/src/main/java/net/ranides/assira/reflection/impl/CGLoader.java

@@ -1,31 +0,0 @@
-package net.ranides.assira.reflection.impl;
-
-import net.ranides.assira.reflection.IClass;
-import net.ranides.assira.reflection.IClassLoader;
-
-public class CGLoader extends ClassLoader implements IClassLoader{
-
-    private static class Li {
-
-        public static final CGLoader SYSTEM = new CGLoader();
-
-    }
-
-    protected CGLoader() {
-        super();
-    }
-
-    public CGLoader(ClassLoader parent) {
-        super(parent);
-    }
-
-    public static IClassLoader system() {
-        return Li.SYSTEM;
-    }
-
-    @Override
-    public IClass<?> defineClass(String name, byte[] bytecode) {
-        return IClass.typeinfo(defineClass(name, bytecode, 0, bytecode.length));
-    }
-
-}

+ 26 - 0
assira/src/main/java/net/ranides/assira/reflection/impl/GCAdapterSForm.java

@@ -0,0 +1,26 @@
+package net.ranides.assira.reflection.impl;
+
+import net.ranides.assira.reflection.AdapterFactory;
+
+import java.io.Serializable;
+
+public class GCAdapterSForm implements Serializable {
+
+    private static final long serialVersionUID = 2L;
+
+    private final String adapter;
+
+    private final Class<?> target;
+
+    private final Object that;
+
+    public GCAdapterSForm(String adapter, Class<?> target, Object that) {
+        this.adapter = adapter;
+        this.target = target;
+        this.that = that;
+    }
+
+    Object readResolve() {
+        return AdapterFactory.getInstance(adapter).cast(target, that);
+    }
+}

+ 36 - 10
assira/src/test/java/net/ranides/assira/reflection/AdapterFactoryTest.java

@@ -1,6 +1,7 @@
 package net.ranides.assira.reflection;
 
 import net.ranides.assira.collection.maps.HashMap;
+import net.ranides.assira.generic.SerializationUtils;
 import net.ranides.assira.reflection.adapter.example.InnerDefs;
 import net.ranides.assira.reflection.adapter.model0.Image0;
 import net.ranides.assira.reflection.adapter.model0.Screen0;
@@ -14,6 +15,7 @@ import net.ranides.assira.reflection.adapter.model3.Image3;
 import net.ranides.assira.reflection.adapter.model3.Screen3;
 import org.junit.Test;
 
+import java.io.IOException;
 import java.util.Arrays;
 
 import static org.junit.Assert.*;
@@ -21,13 +23,37 @@ import static org.junit.Assert.*;
 public class AdapterFactoryTest {
 
 
+    @Test
+    public void serialization() throws IOException {
+        Screen0 screen0 = new Screen0(640, 480);
+
+        Screen1 screen1 = AdapterFactory.getSystem().cast(Screen1.class, screen0);
+
+        assertEquals("640x480 false", screen1.width()+"x"+screen1.height()+" "+screen1.isWide());
+
+        screen1.put("first",4,5);
+        screen1.put(new Image0("second",7,8));
+
+
+        Screen1 screen2 = SerializationUtils.copy(screen1);
+
+        assertEquals("first", screen2.findId(4,5));
+        assertEquals("second", screen2.findId(7,8));
+
+        screen1.put(new Image0("old",3,2));
+        screen2.put(new Image0("new",3,2));
+
+        assertEquals("old", screen1.findId(3,2));
+        assertEquals("new", screen2.findId(3,2));
+    }
+
     @Test
     public void castM1P() {
         Screen0 screen0 = new Screen0(640, 480);
 
-        Screen1P screen1 = AdapterFactory.system().cast(Screen1P.class, screen0);
-        Screen1P screen12 = AdapterFactory.system().cast(Screen1P.class, screen0);
-        Screen1P screen13 = AdapterFactory.system().cast(Screen1P.class, screen0);
+        Screen1P screen1 = AdapterFactory.getSystem().cast(Screen1P.class, screen0);
+        Screen1P screen12 = AdapterFactory.getSystem().cast(Screen1P.class, screen0);
+        Screen1P screen13 = AdapterFactory.getSystem().cast(Screen1P.class, screen0);
 
         assertEquals("640x480 false", screen1.width()+"x"+screen1.height()+" "+screen1.isWide());
 
@@ -45,7 +71,7 @@ public class AdapterFactoryTest {
     public void castM1() {
         Screen0 screen0 = new Screen0(640, 480);
 
-        Screen1 screen1 = AdapterFactory.system().cast(Screen1.class, screen0);
+        Screen1 screen1 = AdapterFactory.getSystem().cast(Screen1.class, screen0);
 
         assertEquals("640x480 false", screen1.width()+"x"+screen1.height()+" "+screen1.isWide());
 
@@ -70,7 +96,7 @@ public class AdapterFactoryTest {
     public void castM2() {
         Screen0 screen0 = new Screen0(640, 480);
 
-        Screen2 screen2 = AdapterFactory.system().cast(Screen2.class, screen0);
+        Screen2 screen2 = AdapterFactory.getSystem().cast(Screen2.class, screen0);
 
         assertEquals("640x480 false", screen2.width()+"x"+screen2.height()+" "+screen2.isWide());
 
@@ -93,8 +119,8 @@ public class AdapterFactoryTest {
 
     @Test
     public void castM3() {
-        Screen3 buffer = AdapterFactory.system().cast(Screen3.class, new Screen0(32,32));
-        Screen3 screen = AdapterFactory.system().cast(Screen3.class, new Screen0(640, 480));
+        Screen3 buffer = AdapterFactory.getSystem().cast(Screen3.class, new Screen0(32,32));
+        Screen3 screen = AdapterFactory.getSystem().cast(Screen3.class, new Screen0(640, 480));
 
         assertEquals("640x480 false", screen.width()+"x"+screen.height()+" "+screen.isWide());
 
@@ -126,7 +152,7 @@ public class AdapterFactoryTest {
     public void castExample() {
         InnerDefs.MutableRecord source = new InnerDefs.MutableRecord(7,3);
 
-        InnerDefs.IRecord3 target3 = AdapterFactory.system().cast(InnerDefs.IRecord3.class, source);
+        InnerDefs.IRecord3 target3 = AdapterFactory.getSystem().cast(InnerDefs.IRecord3.class, source);
 
         assertEquals(7, target3.getX());
         assertEquals(3, target3.getY());
@@ -138,12 +164,12 @@ public class AdapterFactoryTest {
         assertEquals(56, source.resize(4).getX());
         assertEquals(1344, target3.area());
 
-        InnerDefs.IRecord1 target1 = AdapterFactory.system().cast(InnerDefs.IRecord1.class, source);
+        InnerDefs.IRecord1 target1 = AdapterFactory.getSystem().cast(InnerDefs.IRecord1.class, source);
         assertEquals(56, target1.getX());
         assertEquals(24, target1.getY());
         assertEquals(1344, target1.area());
 
-        InnerDefs.IRecord2 target2 = AdapterFactory.system().cast(InnerDefs.IRecord2.class, source);
+        InnerDefs.IRecord2 target2 = AdapterFactory.getSystem().cast(InnerDefs.IRecord2.class, source);
         assertEquals(56, target2.getX());
         assertEquals(24, target2.getY());
         assertEquals(1344, target2.area());

+ 2 - 1
assira/src/test/java/net/ranides/assira/reflection/adapter/model0/Image0.java

@@ -1,8 +1,9 @@
 package net.ranides.assira.reflection.adapter.model0;
 
+import java.io.Serializable;
 import java.util.Objects;
 
-public class Image0 {
+public class Image0 implements Serializable {
 
     private String id;
 

+ 2 - 1
assira/src/test/java/net/ranides/assira/reflection/adapter/model0/Screen0.java

@@ -1,9 +1,10 @@
 package net.ranides.assira.reflection.adapter.model0;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
-public class Screen0 extends AbstractScreen0 {
+public class Screen0 extends AbstractScreen0 implements Serializable {
 
     private int w;