add Class and Proxy type handlers to Serializer

This commit is contained in:
HeshamHM28 2026-01-30 18:11:00 +02:00
parent cbb532fcfd
commit a4ee9ebf4d
2 changed files with 78 additions and 0 deletions

View file

@ -10,6 +10,7 @@ import com.google.gson.JsonPrimitive;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
@ -135,6 +136,26 @@ public final class Serializer {
return new JsonPrimitive((String) obj);
}
// Class objects - serialize as class name string
if (obj instanceof Class) {
return new JsonPrimitive(getClassName((Class<?>) obj));
}
// Dynamic proxies - serialize cleanly without reflection
if (Proxy.isProxyClass(clazz)) {
JsonObject proxyObj = new JsonObject();
proxyObj.addProperty("__proxy__", true);
Class<?>[] interfaces = clazz.getInterfaces();
if (interfaces.length > 0) {
JsonArray interfaceNames = new JsonArray();
for (Class<?> iface : interfaces) {
interfaceNames.add(iface.getName());
}
proxyObj.add("interfaces", interfaceNames);
}
return proxyObj;
}
// Check for circular reference (only for reference types)
if (seen.containsKey(obj)) {
JsonObject circular = new JsonObject();
@ -279,4 +300,15 @@ public final class Serializer {
return jsonObject;
}
/**
* Get a readable class name, handling arrays and primitives.
*/
private static String getClassName(Class<?> clazz) {
if (clazz.isArray()) {
return getClassName(clazz.getComponentType()) + "[]";
}
return clazz.getName();
}
}

View file

@ -4,6 +4,7 @@ import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Proxy;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
@ -250,6 +251,51 @@ class SerializerTest {
}
}
@Nested
@DisplayName("Class and Proxy Types")
class ClassAndProxyTests {
@Test
@DisplayName("should serialize Class objects cleanly")
void testClassObject() {
String json = Serializer.toJson(String.class);
// Should output just the class name, not internal JVM fields
assertEquals("\"java.lang.String\"", json);
}
@Test
@DisplayName("should serialize primitive Class objects")
void testPrimitiveClassObject() {
String json = Serializer.toJson(int.class);
assertEquals("\"int\"", json);
}
@Test
@DisplayName("should serialize array Class objects")
void testArrayClassObject() {
String json = Serializer.toJson(String[].class);
assertEquals("\"java.lang.String[]\"", json);
}
@Test
@DisplayName("should handle dynamic proxy")
void testProxy() {
Runnable proxy = (Runnable) Proxy.newProxyInstance(
Runnable.class.getClassLoader(),
new Class<?>[] { Runnable.class },
(p, method, args) -> null
);
String json = Serializer.toJson(proxy);
assertNotNull(json);
// Should indicate it's a proxy cleanly, not dump handler internals or error
// Current behavior: produces __serialization_error__ due to module access
assertFalse(json.contains("__serialization_error__"),
"Proxy should be serialized cleanly, got: " + json);
assertTrue(json.contains("proxy") || json.contains("Proxy"),
"Proxy should be identified as such, got: " + json);
}
}
// Test helper classes
static class TestPerson {
private final String name;