Pārlūkot izejas kodu

draft: CodeSerializer

new: IOStreams#read
Ranides Atterwim 6 gadi atpakaļ
vecāks
revīzija
832199ab82

+ 109 - 0
assira.drafts/src/main/java/net/ranides/assira/functional/CodeSerializer.java

@@ -0,0 +1,109 @@
+package net.ranides.assira.functional;
+
+import net.ranides.assira.io.IOStreams;
+import net.ranides.assira.io.IOUtils;
+import net.ranides.assira.reflection.IClass;
+import net.ranides.assira.reflection.IClassLoader;
+
+import java.io.*;
+import java.util.*;
+
+public class CodeSerializer {
+
+    public static Serializable withCode(Serializable object) {
+        return new CodeWriter(new ClassWithCode(object));
+    }
+
+    private static IClassLoader LOADER = new IClassLoader("serializer", IClassLoader.getSystem()){
+
+        private final Map<String, byte[]> bytecodes = new HashMap<>();
+
+        private final Map<String, IClass<?>> loaded = new HashMap<>();
+
+        @Override
+        public IClass<?> defineClass(String name, byte[] bytecode) {
+            if(bytecodes.containsKey(name)) {
+                if (Arrays.equals(bytecode, bytecodes.get(name))) {
+                    return loaded.get(name);
+                } else {
+                    throw new IllegalArgumentException("Different bytecode!");
+                }
+            }
+            IClass<?> ic = super.defineClass(name, bytecode);
+            bytecodes.put(name, bytecode);
+            loaded.put(name, ic);
+            return ic;
+        }
+    };
+
+    private static class CodeWriter implements Serializable {
+
+        private final ClassWithCode extern;
+
+        public CodeWriter(ClassWithCode extern) {
+            this.extern = extern;
+        }
+
+        private Object readResolve() {
+            return extern.value;
+        }
+
+    }
+
+    private static class ClassWithCode implements Serializable {
+
+        private static final long serialVersionUID = 4L;
+
+        private String classname;
+
+        private byte[] bytecode;
+
+        private transient Object value;
+
+        public ClassWithCode(Object value) {
+            try {
+                Class<?> ic = value.getClass();
+                try(InputStream is = ic.getClassLoader().getResourceAsStream(ic.getName().replace('.', '/') + ".class")) {
+                    this.classname = ic.getName();
+                    this.bytecode = IOStreams.read(is);
+                    this.value = value;
+                }
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+            out.writeObject(classname);
+            out.writeObject(bytecode);
+
+            ObjectOutputStream oos = new ObjectOutputStream(out);
+            oos.writeObject(value);
+            oos.flush();
+        }
+
+        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
+            classname = (String)in.readObject();
+            bytecode = (byte[]) in.readObject();
+            IClass<?> ic = LOADER.defineClass(classname, bytecode);
+            ObjectInputStreamWithClass oisc = new ObjectInputStreamWithClass(in, ic);
+            this.value = oisc.readObject();
+        }
+
+    }
+
+    private static class ObjectInputStreamWithClass extends ObjectInputStream {
+        private final IClass<?> clazz;
+
+        public ObjectInputStreamWithClass(InputStream in, IClass<?> clazz) throws IOException {
+            super(in);
+            this.clazz = clazz;
+        }
+
+        @SuppressWarnings("rawtypes")
+        protected Class<?> resolveClass(ObjectStreamClass classDesc) throws ClassNotFoundException, IOException {
+            return classDesc.getName().equals(clazz.name()) ? clazz.raw() : super.resolveClass(classDesc);
+        }
+    }
+
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 73 - 0
assira.drafts/src/test/java/net/ranides/assira/functional/CodeSerializerTest.java


+ 8 - 11
assira/src/main/java/net/ranides/assira/io/IOStreams.java

@@ -7,15 +7,7 @@
 
 package net.ranides.assira.io;
 
-import java.io.FilterInputStream;
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.io.Reader;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
+import java.io.*;
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
@@ -51,12 +43,17 @@ public final class IOStreams {
     private IOStreams() {
         /* utility class */
     }
-    
+
+    public static byte[] read(InputStream input) throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream(input.available());
+        copy(input, bos, null);
+        return bos.toByteArray();
+    }
     
     public static long copy(InputStream input, OutputStream output) throws IOException {
         return copy(input, output, null);
     }
-    
+
     public static long copy(InputStream input, OutputStream output, Consumer<Long> callback) throws IOException {
         byte[] buffer = new byte[COPY_BUFFER];
         int n;

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

@@ -16,12 +16,12 @@ public class IClassLoader extends ClassLoader {
         LOADERS.put(SYSTEM.name(), SYSTEM);
     }
 
-    private IClassLoader(String name) {
+    protected IClassLoader(String name) {
         super();
         this.name = name;
     }
 
-    private IClassLoader(String name, ClassLoader parent) {
+    protected IClassLoader(String name, ClassLoader parent) {
         super(parent);
         this.name = name;
     }