STANAANDREY

simple serializer

Sep 22nd, 2025
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 12.65 KB | None | 0 0
  1. package org.example;
  2.  
  3. import java.io.*;
  4. import java.lang.reflect.*;
  5. import java.util.*;
  6.  
  7. class SimpleSerializer {
  8.  
  9.     private final Map<Object, Integer> objToId = new IdentityHashMap<>();
  10.     private final Map<Integer, Object> idToObj = new HashMap<>();
  11.     private int nextId = 1;
  12.  
  13.     // Public API
  14.     public void serialize(Object obj, File file) throws IOException, IllegalAccessException {
  15.         resetState();
  16.         try (PrintWriter out = new PrintWriter(new FileWriter(file))) {
  17.             serializeObject(obj, out);
  18.         }
  19.     }
  20.  
  21.     public Object deserialize(File file) throws Exception {
  22.         resetState();
  23.         List<String> lines = readAllLines(file);
  24.         createEmptyObjects(lines);
  25.         createArrays(lines);
  26.         setFields(lines);
  27.         setArrayElements(lines);
  28.         return idToObj.get(1);
  29.     }
  30.  
  31.     private void resetState() {
  32.         objToId.clear();
  33.         idToObj.clear();
  34.         nextId = 1;
  35.     }
  36.  
  37.     // Serialization
  38.  
  39.     private void serializeObject(Object obj, PrintWriter out) throws IllegalAccessException {
  40.         if (obj == null) return;
  41.  
  42.         if (objToId.containsKey(obj)) return; // Already serialized
  43.  
  44.         int id = nextId++;
  45.         objToId.put(obj, id);
  46.  
  47.         Class<?> cls = obj.getClass();
  48.  
  49.         if (cls.isArray()) {
  50.             serializeArray(obj, out, id);
  51.         } else {
  52.             serializeRegularObject(obj, out, id, cls);
  53.         }
  54.     }
  55.  
  56.     private void serializeArray(Object array, PrintWriter out, int id) throws IllegalAccessException {
  57.         Class<?> compType = array.getClass().getComponentType();
  58.         int length = Array.getLength(array);
  59.         out.printf("arr %d %s %d%n", id, compType.getName(), length);
  60.         for (int i = 0; i < length; i++) {
  61.             Object elem = Array.get(array, i);
  62.             serializeArrayElement(out, id, i, elem, compType);
  63.         }
  64.     }
  65.  
  66.     private void serializeArrayElement(PrintWriter out, int arrId, int index, Object elem, Class<?> compType) throws IllegalAccessException {
  67.         if (elem == null) {
  68.             out.printf("%d[%d]=null%n", arrId, index);
  69.         } else if (isPrimitiveOrWrapper(compType)) {
  70.             out.printf("%d[%d]=%s%n", arrId, index, elem.toString());
  71.         } else if (compType == String.class) {
  72.             out.printf("%d[%d]=%s%n", arrId, index, escapeString((String) elem));
  73.         } else {
  74.             serializeObject(elem, out);
  75.             int refId = objToId.get(elem);
  76.             out.printf("%d[%d]=ref:%d%n", arrId, index, refId);
  77.         }
  78.     }
  79.  
  80.     private void serializeRegularObject(Object obj, PrintWriter out, int id, Class<?> cls) throws IllegalAccessException {
  81.         out.printf("obj %d %s%n", id, cls.getName());
  82.         for (Field field : getAllFields(cls)) {
  83.             field.setAccessible(true);
  84.             Object value = field.get(obj);
  85.             serializeField(out, id, field, value);
  86.         }
  87.     }
  88.  
  89.     private void serializeField(PrintWriter out, int id, Field field, Object value) throws IllegalAccessException {
  90.         if (value == null) {
  91.             out.printf("%d.%s=null%n", id, field.getName());
  92.             return;
  93.         }
  94.  
  95.         Class<?> type = field.getType();
  96.         if (isPrimitiveOrWrapper(type)) {
  97.             out.printf("%d.%s=%s%n", id, field.getName(), value.toString());
  98.         } else if (type == String.class) {
  99.             out.printf("%d.%s=%s%n", id, field.getName(), escapeString((String) value));
  100.         } else {
  101.             serializeObject(value, out);
  102.             int refId = objToId.get(value);
  103.             out.printf("%d.%s=ref:%d%n", id, field.getName(), refId);
  104.         }
  105.     }
  106.  
  107.     // Deserialization
  108.  
  109.     private List<String> readAllLines(File file) throws IOException {
  110.         List<String> lines = new ArrayList<>();
  111.         try (BufferedReader in = new BufferedReader(new FileReader(file))) {
  112.             String line;
  113.             while ((line = in.readLine()) != null) {
  114.                 lines.add(line);
  115.             }
  116.         }
  117.         return lines;
  118.     }
  119.  
  120.     private void createEmptyObjects(List<String> lines) throws Exception {
  121.         for (String line : lines) {
  122.             if (line.startsWith("obj ")) {
  123.                 String[] parts = line.split(" ", 3);
  124.                 int id = Integer.parseInt(parts[1]);
  125.                 String className = parts[2];
  126.                 Class<?> cls = Class.forName(className);
  127.                 Constructor<?> ctor = cls.getDeclaredConstructor();
  128.                 ctor.setAccessible(true);
  129.                 Object instance = ctor.newInstance();
  130.                 idToObj.put(id, instance);
  131.             }
  132.         }
  133.     }
  134.  
  135.     private void createArrays(List<String> lines) throws ClassNotFoundException {
  136.         for (String line : lines) {
  137.             if (line.startsWith("arr ")) {
  138.                 String[] parts = line.split(" ", 4);
  139.                 int id = Integer.parseInt(parts[1]);
  140.                 String compTypeName = parts[2];
  141.                 int length = Integer.parseInt(parts[3]);
  142.                 Class<?> compType = getClassForName(compTypeName);
  143.                 Object array = Array.newInstance(compType, length);
  144.                 idToObj.put(id, array);
  145.             }
  146.         }
  147.     }
  148.  
  149.     private void setFields(List<String> lines) throws Exception {
  150.         for (String line : lines) {
  151.             if (line.startsWith("obj ")) continue;
  152.             if (line.startsWith("arr ")) continue;
  153.             if (line.contains("[")) continue; // array elements handled separately
  154.  
  155.             int dotIndex = line.indexOf('.');
  156.             int eqIndex = line.indexOf('=');
  157.             int id = Integer.parseInt(line.substring(0, dotIndex));
  158.             String fieldName = line.substring(dotIndex + 1, eqIndex);
  159.             String value = line.substring(eqIndex + 1);
  160.  
  161.             Object obj = idToObj.get(id);
  162.             Class<?> cls = obj.getClass();
  163.             Field field = getField(cls, fieldName);
  164.             field.setAccessible(true);
  165.  
  166.             setFieldValue(field, obj, value);
  167.         }
  168.     }
  169.  
  170.     private void setFieldValue(Field field, Object obj, String value) throws Exception {
  171.         Class<?> type = field.getType();
  172.         if (value.equals("null")) {
  173.             field.set(obj, null);
  174.         } else if (isPrimitiveOrWrapper(type)) {
  175.             field.set(obj, parsePrimitive(type, value));
  176.         } else if (type == String.class) {
  177.             field.set(obj, unescapeString(value));
  178.         } else if (value.startsWith("ref:")) {
  179.             int refId = Integer.parseInt(value.substring(4));
  180.             Object refObj = idToObj.get(refId);
  181.             field.set(obj, refObj);
  182.         } else {
  183.             throw new RuntimeException("Unknown value format: " + value);
  184.         }
  185.     }
  186.  
  187.     private void setArrayElements(List<String> lines) throws Exception {
  188.         for (String line : lines) {
  189.             if (!line.contains("[")) continue;
  190.  
  191.             int bracketStart = line.indexOf('[');
  192.             int bracketEnd = line.indexOf(']');
  193.             int eqIndex = line.indexOf('=');
  194.             int id = Integer.parseInt(line.substring(0, bracketStart));
  195.             int index = Integer.parseInt(line.substring(bracketStart + 1, bracketEnd));
  196.             String value = line.substring(eqIndex + 1);
  197.  
  198.             Object array = idToObj.get(id);
  199.             Class<?> compType = array.getClass().getComponentType();
  200.  
  201.             if (value.equals("null")) {
  202.                 Array.set(array, index, null);
  203.             } else if (isPrimitiveOrWrapper(compType)) {
  204.                 Array.set(array, index, parsePrimitive(compType, value));
  205.             } else if (compType == String.class) {
  206.                 Array.set(array, index, unescapeString(value));
  207.             } else if (value.startsWith("ref:")) {
  208.                 int refId = Integer.parseInt(value.substring(4));
  209.                 Object refObj = idToObj.get(refId);
  210.                 Array.set(array, index, refObj);
  211.             } else {
  212.                 throw new RuntimeException("Unknown array element value: " + value);
  213.             }
  214.         }
  215.     }
  216.  
  217.     // Utility methods
  218.  
  219.     private List<Field> getAllFields(Class<?> cls) {
  220.         List<Field> fields = new ArrayList<>();
  221.         while (cls != null && cls != Object.class) {
  222.             fields.addAll(Arrays.asList(cls.getDeclaredFields()));
  223.             cls = cls.getSuperclass();
  224.         }
  225.         return fields;
  226.     }
  227.  
  228.     private Field getField(Class<?> cls, String name) {
  229.         while (cls != null && cls != Object.class) {
  230.             try {
  231.                 return cls.getDeclaredField(name);
  232.             } catch (NoSuchFieldException e) {
  233.                 cls = cls.getSuperclass();
  234.             }
  235.         }
  236.         throw new RuntimeException("Field not found: " + name);
  237.     }
  238.  
  239.     private boolean isPrimitiveOrWrapper(Class<?> cls) {
  240.         return cls.isPrimitive() ||
  241.                 cls == Integer.class || cls == Long.class || cls == Boolean.class ||
  242.                 cls == Byte.class || cls == Character.class || cls == Short.class ||
  243.                 cls == Double.class || cls == Float.class;
  244.     }
  245.  
  246.     private Object parsePrimitive(Class<?> cls, String s) {
  247.         if (cls == int.class || cls == Integer.class) return Integer.parseInt(s);
  248.         if (cls == long.class || cls == Long.class) return Long.parseLong(s);
  249.         if (cls == boolean.class || cls == Boolean.class) return Boolean.parseBoolean(s);
  250.         if (cls == byte.class || cls == Byte.class) return Byte.parseByte(s);
  251.         if (cls == char.class || cls == Character.class) return s.charAt(0);
  252.         if (cls == short.class || cls == Short.class) return Short.parseShort(s);
  253.         if (cls == double.class || cls == Double.class) return Double.parseDouble(s);
  254.         if (cls == float.class || cls == Float.class) return Float.parseFloat(s);
  255.         throw new RuntimeException("Unsupported primitive type: " + cls);
  256.     }
  257.  
  258.     private Class<?> getClassForName(String name) throws ClassNotFoundException {
  259.         return switch (name) {
  260.             case "int" -> int.class;
  261.             case "long" -> long.class;
  262.             case "boolean" -> boolean.class;
  263.             case "byte" -> byte.class;
  264.             case "char" -> char.class;
  265.             case "short" -> short.class;
  266.             case "double" -> double.class;
  267.             case "float" -> float.class;
  268.             default -> Class.forName(name);
  269.         };
  270.     }
  271.  
  272.     private String escapeString(String s) {
  273.         return s.replace("\\", "\\\\")
  274.                 .replace("\n", "\\n")
  275.                 .replace("=", "\\e");
  276.     }
  277.  
  278.  
  279.     private String unescapeString(String s) {
  280.         return s.replace("\\e", "=").replace("\\n", "\n").replace("\\\\", "\\");
  281.     }
  282.  
  283. }
  284.  
  285. public class Main {
  286.  
  287.     // Test program demonstrating all cases
  288.     public static void main(String[] args) throws Exception {
  289.         var serializer = new SimpleSerializer();
  290.  
  291.         // Test classes
  292.         class A {
  293.             int x = 10;
  294.             String s = "hello";
  295.         }
  296.         class B extends A {
  297.             double d = 3.14;
  298.             A ref;
  299.         }
  300.         class C {
  301.             int[] arr = {1, 2, 3};
  302.             B b;
  303.             Object[] objs;
  304.         }
  305.  
  306.         // Create objects with shared references and arrays
  307.         A a1 = new A();
  308.         B b1 = new B();
  309.         b1.ref = a1;
  310.         C c1 = new C();
  311.         c1.b = b1;
  312.         c1.objs = new Object[] {a1, b1, "string", null};
  313.  
  314.         // Show initial objects
  315.         System.out.println("Original objects:");
  316.         System.out.println("a1: x=" + a1.x + ", s=" + a1.s);
  317.         System.out.println("b1: x=" + b1.x + ", s=" + b1.s + ", d=" + b1.d + ", ref=" + b1.ref);
  318.         System.out.println("c1.arr: " + Arrays.toString(c1.arr));
  319.         System.out.println("c1.b: " + c1.b);
  320.         System.out.println("c1.objs: " + Arrays.toString(c1.objs));
  321.  
  322.         // Serialize
  323.         File file = new File("test.ser");
  324.         serializer.serialize(c1, file);
  325.  
  326.         // Deserialize
  327.         Object restored = serializer.deserialize(file);
  328.         C c2 = (C) restored;
  329.  
  330.         // Show restored objects
  331.         System.out.println("\nRestored objects:");
  332.         System.out.println("c2.arr: " + Arrays.toString(c2.arr));
  333.         System.out.println("c2.b: x=" + c2.b.x + ", s=" + c2.b.s + ", d=" + c2.b.d + ", ref=" + c2.b.ref);
  334.         System.out.println("c2.objs: " + Arrays.toString(c2.objs));
  335.  
  336.         // Check shared references
  337.         System.out.println("\nShared reference check:");
  338.         System.out.println("c2.b.ref == c2.objs[0]: " + (c2.b.ref == c2.objs[0]));
  339.  
  340.         // Check array elements
  341.         System.out.println("c2.arr == [1,2,3]: " + Arrays.equals(c2.arr, new int[]{1,2,3}));
  342.     }
  343. }
Advertisement
Add Comment
Please, Sign In to add comment