diff --git a/src/main/java/io/jenkins/plugins/mcp/server/jackson/JenkinsExportedBeanSerializer.java b/src/main/java/io/jenkins/plugins/mcp/server/jackson/JenkinsExportedBeanSerializer.java index 57fbc7a..b08c5c8 100644 --- a/src/main/java/io/jenkins/plugins/mcp/server/jackson/JenkinsExportedBeanSerializer.java +++ b/src/main/java/io/jenkins/plugins/mcp/server/jackson/JenkinsExportedBeanSerializer.java @@ -30,8 +30,9 @@ import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; -import java.io.StringWriter; -import org.kohsuke.stapler.export.Flavor; +import java.lang.reflect.Type; +import org.jvnet.tiger_types.Types; +import org.kohsuke.stapler.export.DataWriter; import org.kohsuke.stapler.export.Model; import org.kohsuke.stapler.export.ModelBuilder; @@ -40,10 +41,103 @@ public class JenkinsExportedBeanSerializer extends JsonSerializer { @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { - StringWriter sw = new StringWriter(); - var dw = Flavor.JSON.createDataWriter(value, sw); + // StringWriter sw = new StringWriter(); + // var dw = Flavor.JSON.createDataWriter(value, sw); Model p = MODEL_BUILDER.get(value.getClass()); - p.writeTo(value, dw); - gen.writeRawValue(sw.toString()); + p.writeTo(value, new JsonGeneratorDataWriter(gen)); + } + + private static class JsonGeneratorDataWriter implements DataWriter { + private final JsonGenerator gen; + Class classAttr; + + public JsonGeneratorDataWriter(JsonGenerator gen) { + this.gen = gen; + classAttr = null; + } + + @Override + public void name(String name) throws IOException { + gen.writeFieldName(name); + } + + @Override + public void valuePrimitive(Object v) throws IOException { + if (v instanceof Integer) { + gen.writeNumber((Integer) v); + } else if (v instanceof Long) { + gen.writeNumber((Long) v); + } else if (v instanceof Float) { + gen.writeNumber((Float) v); + } else if (v instanceof Double) { + gen.writeNumber((Double) v); + } else if (v instanceof Boolean) { + gen.writeBoolean((Boolean) v); + } else if (v instanceof Byte) { + gen.writeNumber((Byte) v); + } else if (v instanceof Short) { + gen.writeNumber((Short) v); + } else if (v instanceof Character) { + gen.writeString(v.toString()); + } else { + throw new IllegalArgumentException("Unsupported primitive type: " + v.getClass()); + } + } + + @Override + public void value(String v) throws IOException { + gen.writeString(v); + } + + @Override + public void valueNull() throws IOException { + gen.writeNull(); + } + + @Override + public void startArray() throws IOException { + gen.writeStartArray(); + } + + @Override + public void endArray() throws IOException { + gen.writeEndArray(); + } + + @Override + public void type(Type expected, Class actual) throws IOException { + classAttr = map(expected, actual); + } + + @Override + public void startObject() throws IOException { + gen.writeStartObject(); + if (classAttr != null) { + name(CLASS_PROPERTY_NAME); + value(classAttr.getName()); + classAttr = null; + } + } + + @Override + public void endObject() throws IOException { + gen.writeEndObject(); + } + + Class map(Type expected, Class actual) { + if (actual == null) { + return null; // nothing to write + } + if (expected == actual) { + return null; // fast pass when we don't need it + } + if (expected == null) { + return actual; // we need to print it + } + if (Types.erasure(expected) == actual) { + return null; // slow pass + } + return actual; + } } }