Changeset 3:1b072f11a3d7 in rrlib_serialization-java


Ignore:
Timestamp:
13.12.2013 02:38:15 (6 years ago)
Author:
Max Reichardt <mreichardt@…>
Branch:
default
Phase:
public
Message:

Added various functionality - to Serialization and GenericObject class in particular

Files:
5 edited

Legend:

Unmodified
Added
Removed
  • BinarySerializable.java

    r0 r3  
    2222package org.rrlib.serialization; 
    2323 
     24import org.rrlib.serialization.rtti.DataType; 
     25 
    2426 
    2527/** 
     
    2931 */ 
    3032public interface BinarySerializable { 
     33 
     34    /** So that binary serializable can be used as type (e.g. in Finroc ports) */ 
     35    public final static DataType<BinarySerializable> TYPE = new DataType<BinarySerializable>(BinarySerializable.class); 
    3136 
    3237    /** 
     
    4348     */ 
    4449    public void deserialize(BinaryInputStream stream) throws Exception; 
     50 
     51    /** 
     52     * Empty Binary serializable 
     53     */ 
     54    public static class Empty implements BinarySerializable { 
     55 
     56        public final static DataType<Empty> TYPE = new DataType<Empty>(Empty.class, "EmptyBinarySerializable"); 
     57 
     58        @Override 
     59        public void serialize(BinaryOutputStream stream) { 
     60        } 
     61 
     62        @Override 
     63        public void deserialize(BinaryInputStream stream) throws Exception { 
     64        } 
     65    } 
    4566} 
  • MemoryBuffer.java

    r0 r3  
    286286    } 
    287287 
     288    public boolean equals(Object other) { 
     289        // two memory buffers are equal if they have the same content (not necessarily the same backend size) 
     290        if (other instanceof MemoryBuffer) { 
     291            MemoryBuffer otherBuffer = (MemoryBuffer)other; 
     292            if (curSize != otherBuffer.curSize) { 
     293                return false; 
     294            } 
     295            for (int i = 0; i < curSize; i++) { 
     296                if (backend.getByte(i) != otherBuffer.backend.getByte(i)) { 
     297                    return false; 
     298                } 
     299            } 
     300            return true; 
     301        } 
     302        return false; 
     303    } 
     304 
    288305    @Override 
    289306    public void applyChange(MemoryBuffer t, long offset, long dummy) { 
  • Serialization.java

    r2 r3  
    2222package org.rrlib.serialization; 
    2323 
     24import java.io.ByteArrayInputStream; 
     25import java.io.ByteArrayOutputStream; 
     26import java.io.IOException; 
     27import java.io.InputStream; 
     28import java.io.ObjectInputStream; 
     29import java.io.ObjectOutputStream; 
     30import java.io.ObjectStreamClass; 
     31import java.io.Serializable; 
     32import java.util.Arrays; 
     33 
    2434import org.rrlib.logging.Log; 
    2535import org.rrlib.logging.LogLevel; 
     36import org.rrlib.serialization.rtti.Copyable; 
    2637import org.rrlib.serialization.rtti.Factory; 
     38import org.rrlib.serialization.rtti.GenericObject; 
    2739import org.rrlib.xml.XMLNode; 
    2840 
     
    5062    /** may only be accessed in synchronized context */ 
    5163    private static final ThreadLocal<MemoryBuffer> buffer = new ThreadLocal<MemoryBuffer>(); 
     64 
     65    /** Classloader to use for deep copies via Java native binary serialization */ 
     66    private static ClassLoader deepCopyClassLoader = Serialization.class.getClassLoader(); 
    5267 
    5368    public static int staticInit() { 
     
    243258    } 
    244259 
    245  
    246     /** 
    247      * Creates deep copy of serializable object 
     260    /** 
     261     * Creates deep copy of object - using the most efficient available way of creating such a copy: 
     262     * 
     263     * (1) Immutable objects are returned directly (as the JVM would provide the same objects for some types anyway) 
     264     * (2) If the Copyable interface is implemented, it is used 
     265     * (3) Binary serialization if available 
     266     * (4) java.io binary serialization if available 
     267     * (5) String serialization if available 
     268     * (6) XML serialization if available 
    248269     * 
    249270     * @param src Object to be copied 
    250      * @param dest Object to copy to 
    251      */ 
    252     public static <T extends BinarySerializable> void deepCopy(T src, T dest, Factory f) { 
    253         MemoryBuffer buf = buffer.get(); 
    254         if (buf == null) { 
    255             buf = new MemoryBuffer(16384); 
    256             buffer.set(buf); 
    257         } 
    258         deepCopyImpl(src, dest, f, buf); 
     271     * @return Object that is a deep copy of src 
     272     */ 
     273    public static <T> T deepCopy(T src) { 
     274        return deepCopy(src, null, null); 
     275    } 
     276 
     277    /** 
     278     * Creates deep copy of object - using the most efficient available way of creating such a copy: 
     279     * 
     280     * (1) Immutable objects are returned directly (as the JVM would provide the same objects for some types anyway) 
     281     * (2) If the Copyable interface is implemented, it is used 
     282     * (3) Binary serialization if available 
     283     * (4) java.io binary serialization if available 
     284     * (5) String serialization if available 
     285     * (6) XML serialization if available 
     286     * 
     287     * @param src Object to be copied 
     288     * @param dest Object to copy to (optional; will contain result of copy, in case type is a mutable type) 
     289     * @return Object that is a deep copy of src 
     290     */ 
     291    public static <T> T deepCopy(T src, T dest) { 
     292        return deepCopy(src, dest, null); 
     293    } 
     294 
     295    /** 
     296     * Creates deep copy of object - using the most efficient available way of creating such a copy: 
     297     * 
     298     * (1) Immutable objects are returned directly (as the JVM would provide the same objects for some types anyway) 
     299     * (2) If the Copyable interface is implemented, it is used 
     300     * (3) Binary serialization if available 
     301     * (4) java.io binary serialization if available 
     302     * (5) String serialization if available 
     303     * (6) XML serialization if available 
     304     * 
     305     * @param src Object to be copied 
     306     * @param dest Object to copy to (optional; will contain result of copy, in case type is a mutable type) 
     307     * @param f Factory to use (optional) 
     308     * @return Object that is a deep copy of src 
     309     */ 
     310    @SuppressWarnings({ "unchecked", "rawtypes" }) 
     311    public static <T> T deepCopy(T src, T dest, Factory f) { 
     312        if (src == null) { 
     313            return null; 
     314        } 
     315        Class<?> type = src.getClass(); 
     316        if (type.isPrimitive() || Number.class.isAssignableFrom(type) || Boolean.class.equals(type) || String.class.equals(type)) { 
     317            return src; 
     318        } 
     319        if (dest == null || dest.getClass() != type) { 
     320            try { 
     321                dest = (T)type.newInstance(); 
     322            } catch (Exception e) { 
     323                throw new RuntimeException(e); 
     324            } 
     325        } 
     326        if (Copyable.class.isAssignableFrom(type)) { 
     327            ((Copyable)dest).copyFrom(src); 
     328            return dest; 
     329        } else if (BinarySerializable.class.isAssignableFrom(type)) { 
     330            MemoryBuffer buf = buffer.get(); 
     331            if (buf == null) { 
     332                buf = new MemoryBuffer(16384); 
     333                buffer.set(buf); 
     334            } 
     335            deepCopyImpl((BinarySerializable)src, (BinarySerializable)dest, f, buf); 
     336            return dest; 
     337        } 
     338        try { 
     339            if (Serializable.class.isAssignableFrom(type)) { 
     340                ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     341                ObjectOutputStream oos = new ObjectOutputStream(baos); 
     342                oos.writeObject(src); 
     343                oos.close(); 
     344                baos.close(); 
     345                ObjectInputStream ois = new ObjectInputStreamUsingPluginClassLoader(new ByteArrayInputStream(baos.toByteArray())); 
     346                dest = (T)ois.readObject(); 
     347                ois.close(); 
     348            } else if (StringSerializable.class.isAssignableFrom(type)) { 
     349                String string = serialize(src); 
     350                dest = (T)new StringInputStream(string).readObject(dest, type); 
     351            } else if (XMLSerializable.class.isAssignableFrom(type)) { 
     352                MemoryBuffer buf = buffer.get(); 
     353                if (buf == null) { 
     354                    buf = new MemoryBuffer(16384); 
     355                    buffer.set(buf); 
     356                } 
     357                buf.clear(); 
     358                BinaryOutputStream stream = new BinaryOutputStream(buf); 
     359                stream.writeObject(src, type, DataEncoding.XML); 
     360                stream.close(); 
     361                BinaryInputStream istream = new BinaryInputStream(buf); 
     362                dest = (T)istream.readObject(dest, type); 
     363            } else { 
     364                throw new RuntimeException("Object of type " + src.getClass().getName() + " cannot be deep-copied"); 
     365            } 
     366        } catch (Exception e) { 
     367            throw new RuntimeException(e); 
     368        } 
     369        return dest; 
    259370    } 
    260371 
     
    266377     * @param buf Memory buffer to use 
    267378     */ 
    268     public static <T extends BinarySerializable> void deepCopyImpl(T src, T dest, Factory f, MemoryBuffer buf) { 
     379    private static <T extends BinarySerializable> void deepCopyImpl(T src, T dest, Factory f, MemoryBuffer buf) { 
    269380        buf.clear(); 
    270381        BinaryOutputStream os = new BinaryOutputStream(buf); 
     
    283394    } 
    284395 
    285 //    /** 
    286 //     * Serialization-based equals()-method 
    287 //     * (not very efficient/RT-capable - should therefore not be called regular loops) 
    288 //     * 
    289 //     * @param obj1 Object1 
    290 //     * @param obj2 Object2 
    291 //     * @returns true if both objects are serialized to the same binary data (usually they are equal then) 
    292 //     */ 
    293 //    public static boolean equals(GenericObject obj1, GenericObject obj2) { 
    294 //        if (obj1 == obj2) { 
    295 //            return true; 
    296 //        } 
    297 //        if (obj1 == null || obj2 == null || obj1.getType() != obj2.getType()) { 
    298 //            return false; 
    299 //        } 
    300 // 
    301 //        MemoryBuffer buf1 = new MemoryBuffer(); 
    302 //        MemoryBuffer buf2 = new MemoryBuffer(); 
    303 //        BinaryOutputStream os1 = new BinaryOutputStream(buf1); 
    304 //        BinaryOutputStream os2 = new BinaryOutputStream(buf2); 
    305 //        obj1.serialize(os1); 
    306 //        obj2.serialize(os2); 
    307 //        os1.close(); 
    308 //        os2.close(); 
    309 // 
    310 //        if (buf1.getSize() != buf2.getSize()) { 
    311 //            return false; 
    312 //        } 
    313 // 
    314 //        BinaryInputStream is1 = new BinaryInputStream(buf1); 
    315 //        BinaryInputStream is2 = new BinaryInputStream(buf2); 
    316 // 
    317 //        for (int i = 0; i < buf1.getSize(); i++) { 
    318 //            if (is1.readByte() != is2.readByte()) { 
    319 //                return false; 
    320 //            } 
    321 //        } 
    322 //        return true; 
    323 //    } 
     396    /** 
     397     * Serialization-based equals()-method 
     398     * (not very efficient - should therefore not be called regular loops) 
     399     * 
     400     * @param obj1 Object1 
     401     * @param obj2 Object2 
     402     * @returns True if both objects are serialized to the same data (usually they are equal then) 
     403     */ 
     404    public static boolean equals(Object obj1, Object obj2) { 
     405        if (obj1 == obj2) { 
     406            return true; 
     407        } 
     408        if (obj1 == null || obj2 == null || obj1.getClass() != obj2.getClass()) { 
     409            return false; 
     410        } 
     411        if (obj1 instanceof GenericObject) { 
     412            return equals((GenericObject)obj1, (GenericObject)obj2); 
     413        } 
     414        if (obj1 instanceof BinarySerializable) { 
     415            MemoryBuffer buf1 = new MemoryBuffer(); 
     416            MemoryBuffer buf2 = new MemoryBuffer(); 
     417            BinaryOutputStream os1 = new BinaryOutputStream(buf1); 
     418            BinaryOutputStream os2 = new BinaryOutputStream(buf2); 
     419            os1.writeObject(obj1); 
     420            os2.writeObject(obj2); 
     421            os1.close(); 
     422            os2.close(); 
     423            return buf1.equals(buf2); 
     424        } else if (obj1 instanceof Serializable) { 
     425            return Arrays.equals(toByteArray((Serializable)obj1), toByteArray((Serializable)obj2)); 
     426        } else if (obj1 instanceof StringSerializable) { 
     427            return serialize(obj1).equals(serialize(obj2)); 
     428        } else if (obj1 instanceof XMLSerializable) { 
     429            MemoryBuffer buf1 = new MemoryBuffer(); 
     430            MemoryBuffer buf2 = new MemoryBuffer(); 
     431            BinaryOutputStream os1 = new BinaryOutputStream(buf1); 
     432            BinaryOutputStream os2 = new BinaryOutputStream(buf2); 
     433            os1.writeObject(obj1, obj1.getClass(), DataEncoding.XML); 
     434            os2.writeObject(obj2, obj2.getClass(), DataEncoding.XML); 
     435            os1.close(); 
     436            os2.close(); 
     437            return buf1.equals(buf2); 
     438        } else { 
     439            throw new RuntimeException("Objects of type " + obj1.getClass().getName() + " cannot be serialized and compared"); 
     440        } 
     441    } 
     442 
     443    /** 
     444     * Serializes Java-Serializable object to byte array 
     445     * 
     446     * @param t Object to serialize 
     447     * @return Byte array containing serialized object 
     448     */ 
     449    public static byte[] toByteArray(Serializable t) { 
     450        try { 
     451            ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     452            ObjectOutputStream oos = new ObjectOutputStream(baos); 
     453            oos.writeObject(t); 
     454            oos.close(); 
     455            return baos.toByteArray(); 
     456        } catch (Exception e) { 
     457            throw new RuntimeException("Converting object to byte array failed", e); 
     458        } 
     459    } 
    324460 
    325461    /** 
     
    332468        vector.resize(newSize); 
    333469    } 
     470 
     471    /** 
     472     * TODO: check whether there's a more elegant way 
     473     * 
     474     * Set class loader used for deep copies. 
     475     * This is only necessary if classes are to be cloned that are accessible 
     476     * by a different class loader only. 
     477     * 
     478     * @param classLoader Class Loader to use 
     479     */ 
     480    static public void setDeepCopyClassLoader(ClassLoader classLoader) { 
     481        deepCopyClassLoader = classLoader; 
     482    } 
     483 
     484    /** 
     485     * @author jens 
     486     * 
     487     * Local helper class for resolving classes via plugin class loader. 
     488     */ 
     489    private static class ObjectInputStreamUsingPluginClassLoader extends ObjectInputStream { 
     490 
     491        @Override 
     492        public Class<?> resolveClass(ObjectStreamClass descriptor) throws IOException, ClassNotFoundException { 
     493            try { 
     494                return deepCopyClassLoader.loadClass(descriptor.getName()); 
     495            } catch (Exception e) { 
     496            } 
     497            return super.resolveClass(descriptor); 
     498        } 
     499 
     500        public ObjectInputStreamUsingPluginClassLoader(InputStream in) throws IOException { 
     501            super(in); 
     502        } 
     503 
     504    } 
    334505} 
  • rtti/DataType.java

    r1 r3  
    2525import java.util.ArrayList; 
    2626 
    27 import org.rrlib.serialization.BinaryInputStream; 
    28 import org.rrlib.serialization.BinaryOutputStream; 
    29 import org.rrlib.serialization.BinarySerializable; 
    3027import org.rrlib.serialization.EnumValue; 
    3128import org.rrlib.serialization.PortDataListImpl; 
    32 import org.rrlib.serialization.Serialization; 
    3329 
    3430/** 
     
    106102        } 
    107103 
    108         @SuppressWarnings({ "unchecked", "rawtypes" }) 
    109104        @Override 
    110105        public GenericObject createInstanceGeneric() { 
  • rtti/GenericObject.java

    r1 r3  
    2121//---------------------------------------------------------------------- 
    2222package org.rrlib.serialization.rtti; 
     23 
     24import org.rrlib.serialization.BinaryInputStream; 
     25import org.rrlib.serialization.BinaryOutputStream; 
     26import org.rrlib.serialization.Serialization; 
     27import org.rrlib.serialization.StringInputStream; 
     28import org.rrlib.serialization.StringOutputStream; 
     29import org.rrlib.xml.XMLNode; 
    2330 
    2431 
     
    6269    } 
    6370 
    64 //    /** 
    65 //     * Deep copy source object to this object 
    66 //     * (types MUST match) 
    67 //     * 
    68 //     * @param source Source object 
    69 //     */ 
    70 //    @SuppressWarnings({ "unchecked", "rawtypes" }) 
    71 //    public void deepCopyFrom(GenericObject source, Factory f) { 
    72 //        if (source.type == type) { 
    73 //            deepCopyFrom((Object)source.wrapped, f); 
    74 //        } else if (Copyable.class.isAssignableFrom(type.getJavaClass())) { 
    75 //            ((Copyable)wrapped).copyFrom(source.wrapped); 
    76 //        } else { 
    77 //            throw new RuntimeException("Types must match"); 
    78 //        } 
    79 //    } 
    80 // 
    81 //    /** 
    82 //     * Deep copy source object to this object 
    83 //     * (types MUST match) 
    84 //     * 
    85 //     * @param source Source object 
    86 //     */ 
    87 //    protected void deepCopyFrom(Object source, Factory f) 
     71    /** 
     72     * Deep copy source object to this object 
     73     * 
     74     * @param source Source object 
     75     */ 
     76    public void deepCopyFrom(GenericObject source, Factory f) { 
     77        wrapped = Serialization.deepCopy(source.wrapped, wrapped, f); 
     78        type = source.type; 
     79    } 
    8880 
    8981    /** 
     
    10496    } 
    10597 
    106 //    /** 
    107 //     * Deserialize data from binary input stream - possibly using non-binary encoding. 
    108 //     * 
    109 //     * @param is Binary input stream 
    110 //     * @param enc Encoding to use 
    111 //     */ 
    112 //    public void deserialize(BinaryInputStream is, DataEncoding enc) { 
    113 //        Serialization.deserialize(is, getData(), enc); 
    114 //    } 
    115 // 
    116 //    /** 
    117 //     * Serialize data to binary output stream - possibly using non-binary encoding. 
    118 //     * 
    119 //     * @param os Binary output stream 
    120 //     * @param enc Encoding to use 
    121 //     */ 
    122 //    public void serialize(BinaryOutputStream os, DataEncoding enc) { 
    123 //        Serialization.serialize(os, getData(), enc); 
    124 //    } 
     98    /** 
     99     * Deserialize data from binary input stream - possibly using non-binary encoding. 
     100     * 
     101     * @param stream Binary input stream 
     102     * @param enc Encoding to use 
     103     */ 
     104    public void deserialize(BinaryInputStream stream, Serialization.DataEncoding enc) throws Exception { 
     105        wrapped = stream.readObject(wrapped, type.getJavaClass(), enc); 
     106    } 
     107 
     108    /** 
     109     * Serialize data to binary output stream - possibly using non-binary encoding. 
     110     * 
     111     * @param stream Binary output stream 
     112     * @param enc Encoding to use 
     113     */ 
     114    public void serialize(BinaryOutputStream stream, Serialization.DataEncoding enc) { 
     115        stream.writeObject(getData(), type.getJavaClass(), enc); 
     116    } 
     117 
     118    /** 
     119     * Deserialize data from string stream 
     120     * 
     121     * @param stream String output stream 
     122     */ 
     123    public void deserialize(StringInputStream stream) throws Exception { 
     124        wrapped = stream.readObject(wrapped, type.getJavaClass()); 
     125    } 
     126 
     127    /** 
     128     * Serialize data to string stream 
     129     * 
     130     * @param node String input stream 
     131     */ 
     132    public void serialize(StringOutputStream stream) throws Exception { 
     133        stream.appendObject(wrapped, type.getJavaClass()); 
     134    } 
     135 
     136    /** 
     137     * Deserialize data from XML node 
     138     * 
     139     * @param node XML node 
     140     */ 
     141    public void deserialize(XMLNode node) throws Exception { 
     142        wrapped = Serialization.deserialize(node, wrapped, type.getJavaClass()); 
     143    } 
     144 
     145    /** 
     146     * Serialize data to XML node 
     147     * 
     148     * @param node XML node 
     149     */ 
     150    public void serialize(XMLNode node) throws Exception { 
     151        Serialization.serialize(node, this); 
     152    } 
    125153 
    126154} 
Note: See TracChangeset for help on using the changeset viewer.