Skip to content

Commit 5255ad3

Browse files
committed
refactor(util): Replace JsonHelper with ObjectMappers for JSON and YAML processing
1 parent 38aeaa3 commit 5255ad3

File tree

9 files changed

+63
-105
lines changed

9 files changed

+63
-105
lines changed

src/main/java/com/github/codeboyzhou/mcp/declarative/McpServers.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,13 @@ public void startSseServer(McpSseServerInfo serverInfo) {
5252

5353
public void startServer(String configFileName) {
5454
Assert.notNull(configFileName, "configFileName must not be null");
55-
doStartServer(new YAMLConfigurationLoader(configFileName).getConfig());
55+
YAMLConfigurationLoader configLoader = new YAMLConfigurationLoader(configFileName);
56+
doStartServer(configLoader.loadConfig());
5657
}
5758

5859
public void startServer() {
59-
doStartServer(new YAMLConfigurationLoader().getConfig());
60+
YAMLConfigurationLoader configLoader = new YAMLConfigurationLoader();
61+
doStartServer(configLoader.loadConfig());
6062
}
6163

6264
private void doStartServer(McpServerConfiguration configuration) {

src/main/java/com/github/codeboyzhou/mcp/declarative/common/BufferQueue.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.github.codeboyzhou.mcp.declarative.common;
22

3-
import com.github.codeboyzhou.mcp.declarative.util.JsonHelper;
3+
import com.github.codeboyzhou.mcp.declarative.util.ObjectMappers;
44
import java.util.concurrent.BlockingQueue;
55
import java.util.concurrent.Executors;
66
import java.util.concurrent.LinkedBlockingQueue;
@@ -33,7 +33,7 @@ public BufferQueue() {
3333
public void submit(T component) {
3434
try {
3535
queue.put(component);
36-
logger.debug("Component submitted to queue: {}", JsonHelper.toJson(component));
36+
logger.debug("Component submitted to queue: {}", ObjectMappers.toJson(component));
3737
} catch (InterruptedException e) {
3838
Thread.currentThread().interrupt();
3939
}
@@ -48,7 +48,8 @@ public void consume(Consumer<T> consumer) {
4848
while (!Thread.interrupted()) {
4949
T component = queue.take();
5050
consumer.accept(component);
51-
logger.debug("Component consumed from queue: {}", JsonHelper.toJson(component));
51+
logger.debug(
52+
"Component consumed from queue: {}", ObjectMappers.toJson(component));
5253
TimeUnit.MILLISECONDS.sleep(delayMillis);
5354
}
5455
} catch (InterruptedException e) {
Lines changed: 7 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,35 @@
11
package com.github.codeboyzhou.mcp.declarative.configuration;
22

3-
import com.fasterxml.jackson.databind.ObjectMapper;
4-
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
53
import com.github.codeboyzhou.mcp.declarative.exception.McpServerException;
6-
import java.io.IOException;
4+
import com.github.codeboyzhou.mcp.declarative.util.ObjectMappers;
75
import java.net.URISyntaxException;
86
import java.net.URL;
9-
import java.nio.file.FileSystems;
107
import java.nio.file.Path;
118
import java.nio.file.Paths;
12-
import java.nio.file.StandardWatchEventKinds;
13-
import java.nio.file.WatchEvent;
14-
import java.nio.file.WatchKey;
15-
import java.nio.file.WatchService;
16-
import java.util.List;
179
import org.slf4j.Logger;
1810
import org.slf4j.LoggerFactory;
1911

2012
public final class YAMLConfigurationLoader {
2113

2214
private static final Logger logger = LoggerFactory.getLogger(YAMLConfigurationLoader.class);
2315

24-
private static final ObjectMapper YAML_MAPPER = new ObjectMapper(new YAMLFactory());
25-
2616
private static final String CONFIG_FILE_NAME = "mcp-server.yml";
2717

28-
private static final String WATCH_THREAD_NAME = "McpServerConfigFileWatcher";
29-
3018
private final String configFileName;
3119

32-
private WatchService watchService;
33-
34-
private McpServerConfiguration config;
35-
3620
public YAMLConfigurationLoader(String configFileName) {
3721
this.configFileName = configFileName;
38-
initializeWatchService();
39-
loadConfig();
4022
}
4123

4224
public YAMLConfigurationLoader() {
4325
this(CONFIG_FILE_NAME);
4426
}
4527

46-
public McpServerConfiguration getConfig() {
28+
public McpServerConfiguration loadConfig() {
29+
Path configFilePath = getConfigFilePath(configFileName);
30+
McpServerConfiguration config =
31+
ObjectMappers.fromYaml(configFilePath.toFile(), McpServerConfiguration.class);
32+
logger.info("Configuration loaded successfully from file: {}", configFileName);
4733
return config;
4834
}
4935

@@ -57,52 +43,7 @@ private Path getConfigFilePath(String fileName) {
5743
return Paths.get(configFileUrl.toURI());
5844
} catch (URISyntaxException e) {
5945
// should never happen
60-
return null;
61-
}
62-
}
63-
64-
private void initializeWatchService() {
65-
try {
66-
Path configFilePath = getConfigFilePath(configFileName);
67-
assert configFilePath != null;
68-
Path parentPath = configFilePath.getParent();
69-
watchService = FileSystems.getDefault().newWatchService();
70-
parentPath.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
71-
72-
Thread watchThread = new Thread(this::watchConfigFile, WATCH_THREAD_NAME);
73-
watchThread.setDaemon(true);
74-
watchThread.start();
75-
} catch (IOException e) {
76-
logger.error("Failed to initialize configuration file watch service", e);
77-
}
78-
}
79-
80-
private void watchConfigFile() {
81-
try {
82-
while (true) {
83-
WatchKey watchKey = watchService.take();
84-
List<WatchEvent<?>> watchEvents = watchKey.pollEvents();
85-
for (WatchEvent<?> event : watchEvents) {
86-
if (event.context().toString().equals(configFileName)) {
87-
loadConfig();
88-
}
89-
}
90-
watchKey.reset();
91-
}
92-
} catch (InterruptedException e) {
93-
Thread.currentThread().interrupt();
94-
logger.error("Configuration file watch service interrupted", e);
95-
}
96-
}
97-
98-
private void loadConfig() {
99-
try {
100-
Path configFilePath = getConfigFilePath(configFileName);
101-
assert configFilePath != null;
102-
config = YAML_MAPPER.readValue(configFilePath.toFile(), McpServerConfiguration.class);
103-
logger.info("Configuration loaded successfully");
104-
} catch (IOException e) {
105-
logger.error("Failed to reload configuration", e);
46+
throw new McpServerException("Invalid configuration file path: " + fileName, e);
10647
}
10748
}
10849
}

src/main/java/com/github/codeboyzhou/mcp/declarative/server/factory/McpServerPromptFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import com.github.codeboyzhou.mcp.declarative.annotation.McpPromptParam;
77
import com.github.codeboyzhou.mcp.declarative.annotation.McpPrompts;
88
import com.github.codeboyzhou.mcp.declarative.common.BufferQueue;
9-
import com.github.codeboyzhou.mcp.declarative.util.JsonHelper;
9+
import com.github.codeboyzhou.mcp.declarative.util.ObjectMappers;
1010
import com.github.codeboyzhou.mcp.declarative.util.StringHelper;
1111
import com.github.codeboyzhou.mcp.declarative.util.TypeConverter;
1212
import com.google.inject.Inject;
@@ -47,7 +47,7 @@ public McpServerFeatures.AsyncPromptSpecification create(Class<?> clazz, Method
4747
final String description = resolveComponentAttributeValue(promptMethod.description());
4848
List<McpSchema.PromptArgument> promptArguments = createPromptArguments(method);
4949
McpSchema.Prompt prompt = new McpSchema.Prompt(name, title, description, promptArguments);
50-
logger.debug("Registering prompt: {}", JsonHelper.toJson(prompt));
50+
logger.debug("Registering prompt: {}", ObjectMappers.toJson(prompt));
5151
return new McpServerFeatures.AsyncPromptSpecification(
5252
prompt,
5353
(exchange, request) ->

src/main/java/com/github/codeboyzhou/mcp/declarative/server/factory/McpServerResourceFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.github.codeboyzhou.mcp.declarative.annotation.McpResource;
66
import com.github.codeboyzhou.mcp.declarative.annotation.McpResources;
77
import com.github.codeboyzhou.mcp.declarative.common.BufferQueue;
8-
import com.github.codeboyzhou.mcp.declarative.util.JsonHelper;
8+
import com.github.codeboyzhou.mcp.declarative.util.ObjectMappers;
99
import com.github.codeboyzhou.mcp.declarative.util.StringHelper;
1010
import com.google.inject.Inject;
1111
import com.google.inject.Injector;
@@ -47,7 +47,7 @@ public McpServerFeatures.AsyncResourceSpecification create(Class<?> clazz, Metho
4747
.mimeType(res.mimeType())
4848
.annotations(new McpSchema.Annotations(List.of(res.roles()), res.priority()))
4949
.build();
50-
logger.debug("Registering resource: {}", JsonHelper.toJson(resource));
50+
logger.debug("Registering resource: {}", ObjectMappers.toJson(resource));
5151
return new McpServerFeatures.AsyncResourceSpecification(
5252
resource,
5353
(exchange, request) ->

src/main/java/com/github/codeboyzhou/mcp/declarative/server/factory/McpServerToolFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import com.github.codeboyzhou.mcp.declarative.annotation.McpTools;
1010
import com.github.codeboyzhou.mcp.declarative.common.BufferQueue;
1111
import com.github.codeboyzhou.mcp.declarative.enums.JsonSchemaDataType;
12-
import com.github.codeboyzhou.mcp.declarative.util.JsonHelper;
12+
import com.github.codeboyzhou.mcp.declarative.util.ObjectMappers;
1313
import com.github.codeboyzhou.mcp.declarative.util.StringHelper;
1414
import com.github.codeboyzhou.mcp.declarative.util.TypeConverter;
1515
import com.google.inject.Inject;
@@ -58,7 +58,7 @@ public McpServerFeatures.AsyncToolSpecification create(Class<?> clazz, Method me
5858
.description(description)
5959
.inputSchema(paramSchema)
6060
.build();
61-
logger.debug("Registering tool: {}", JsonHelper.toJson(tool));
61+
logger.debug("Registering tool: {}", ObjectMappers.toJson(tool));
6262
return McpServerFeatures.AsyncToolSpecification.builder()
6363
.tool(tool)
6464
.callHandler(

src/main/java/com/github/codeboyzhou/mcp/declarative/util/JsonHelper.java

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.github.codeboyzhou.mcp.declarative.util;
2+
3+
import com.fasterxml.jackson.core.JsonFactory;
4+
import com.fasterxml.jackson.core.JsonProcessingException;
5+
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
7+
import com.github.codeboyzhou.mcp.declarative.exception.McpServerException;
8+
import java.io.File;
9+
import java.io.IOException;
10+
import org.jetbrains.annotations.VisibleForTesting;
11+
12+
public final class ObjectMappers {
13+
14+
public static final ObjectMapper JSON_MAPPER = new ObjectMapper(new JsonFactory());
15+
16+
private static final ObjectMapper YAML_MAPPER = new ObjectMapper(new YAMLFactory());
17+
18+
@VisibleForTesting
19+
ObjectMappers() {
20+
throw new UnsupportedOperationException("Utility class should not be instantiated");
21+
}
22+
23+
public static String toJson(Object object) {
24+
try {
25+
return JSON_MAPPER.writeValueAsString(object);
26+
} catch (JsonProcessingException e) {
27+
throw new McpServerException("Error converting object to JSON", e);
28+
}
29+
}
30+
31+
public static <T> T fromYaml(File yamlFile, Class<T> valueType) {
32+
try {
33+
return YAML_MAPPER.readValue(yamlFile, valueType);
34+
} catch (IOException e) {
35+
throw new McpServerException("Error reading YAML file: " + yamlFile.getAbsolutePath(), e);
36+
}
37+
}
38+
}

src/test/java/com/github/codeboyzhou/mcp/declarative/util/JsonHelperTest.java renamed to src/test/java/com/github/codeboyzhou/mcp/declarative/util/ObjectMappersTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
import com.github.codeboyzhou.mcp.declarative.exception.McpServerException;
88
import org.junit.jupiter.api.Test;
99

10-
class JsonHelperTest {
10+
class ObjectMappersTest {
1111

1212
record TestClass(String name, int age) {}
1313

1414
@Test
1515
void testNewInstance() {
1616
UnsupportedOperationException e =
17-
assertThrows(UnsupportedOperationException.class, JsonHelper::new);
17+
assertThrows(UnsupportedOperationException.class, ObjectMappers::new);
1818
assertEquals("Utility class should not be instantiated", e.getMessage());
1919
}
2020

@@ -23,10 +23,10 @@ void testToJson() {
2323
assertDoesNotThrow(
2424
() -> {
2525
TestClass testObject = new TestClass("test", 18);
26-
assertEquals("{\"name\":\"test\",\"age\":18}", JsonHelper.toJson(testObject));
26+
assertEquals("{\"name\":\"test\",\"age\":18}", ObjectMappers.toJson(testObject));
2727
});
2828

29-
McpServerException e = assertThrows(McpServerException.class, () -> JsonHelper.toJson(this));
29+
McpServerException e = assertThrows(McpServerException.class, () -> ObjectMappers.toJson(this));
3030
assertEquals("Error converting object to JSON", e.getMessage());
3131
}
3232
}

0 commit comments

Comments
 (0)