add Class and Proxy type handlers to Serializer
This commit is contained in:
parent
cbb532fcfd
commit
a4ee9ebf4d
2 changed files with 78 additions and 0 deletions
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue