Skip to content

Commit 4f4cab0

Browse files
committed
Adjust packages in mcp-json-jackson2 to jackson2 packages
deprecate classes for removal in `io.modelcontextprotocol.json.jackson`/`io.modelcontextprotocol.json.schema.jackson` and copy them to `io.modelcontextprotocol.json.jackson2`/`io.modelcontextprotocol.json.schema.jackson2` in non-deprecated form.
1 parent 007f2a0 commit 4f4cab0

12 files changed

+1142
-4
lines changed

mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson/JacksonMcpJsonMapper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@
1414
/**
1515
* Jackson-based implementation of JsonMapper. Wraps a Jackson ObjectMapper but keeps the
1616
* SDK decoupled from Jackson at the API level.
17+
*
18+
* @deprecated since 18.0.0, use
19+
* {@link io.modelcontextprotocol.json.jackson2.JacksonMcpJsonMapper} instead. Will be
20+
* removed in 19.0.0
1721
*/
22+
@Deprecated(forRemoval = true, since = "18.0.0")
1823
public final class JacksonMcpJsonMapper implements McpJsonMapper {
1924

2025
private final ObjectMapper objectMapper;

mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/jackson/JacksonMcpJsonMapperSupplier.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@
1313
* <p>
1414
* This implementation provides a {@link McpJsonMapper} backed by a Jackson
1515
* {@link com.fasterxml.jackson.databind.ObjectMapper}.
16+
*
17+
* @deprecated since 18.0.0, use
18+
* {@link io.modelcontextprotocol.json.jackson2.JacksonMcpJsonMapperSupplier} instead.
19+
* Will be removed in 19.0.0.
1620
*/
21+
@Deprecated(forRemoval = true, since = "18.0.0")
1722
public class JacksonMcpJsonMapperSupplier implements McpJsonMapperSupplier {
1823

1924
/**
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2026 - 2026 the original author or authors.
3+
*/
4+
5+
package io.modelcontextprotocol.json.jackson2;
6+
7+
import java.io.IOException;
8+
9+
import com.fasterxml.jackson.databind.JavaType;
10+
import com.fasterxml.jackson.databind.ObjectMapper;
11+
12+
import io.modelcontextprotocol.json.McpJsonMapper;
13+
import io.modelcontextprotocol.json.TypeRef;
14+
15+
/**
16+
* Jackson-based implementation of JsonMapper. Wraps a Jackson ObjectMapper but keeps the
17+
* SDK decoupled from Jackson at the API level.
18+
*/
19+
public final class JacksonMcpJsonMapper implements McpJsonMapper {
20+
21+
private final ObjectMapper objectMapper;
22+
23+
/**
24+
* Constructs a new JacksonMcpJsonMapper instance with the given ObjectMapper.
25+
* @param objectMapper the ObjectMapper to be used for JSON serialization and
26+
* deserialization. Must not be null.
27+
* @throws IllegalArgumentException if the provided ObjectMapper is null.
28+
*/
29+
public JacksonMcpJsonMapper(ObjectMapper objectMapper) {
30+
if (objectMapper == null) {
31+
throw new IllegalArgumentException("ObjectMapper must not be null");
32+
}
33+
this.objectMapper = objectMapper;
34+
}
35+
36+
/**
37+
* Returns the underlying Jackson {@link ObjectMapper} used for JSON serialization and
38+
* deserialization.
39+
* @return the ObjectMapper instance
40+
*/
41+
public ObjectMapper getObjectMapper() {
42+
return objectMapper;
43+
}
44+
45+
@Override
46+
public <T> T readValue(String content, Class<T> type) throws IOException {
47+
return objectMapper.readValue(content, type);
48+
}
49+
50+
@Override
51+
public <T> T readValue(byte[] content, Class<T> type) throws IOException {
52+
return objectMapper.readValue(content, type);
53+
}
54+
55+
@Override
56+
public <T> T readValue(String content, TypeRef<T> type) throws IOException {
57+
JavaType javaType = objectMapper.getTypeFactory().constructType(type.getType());
58+
return objectMapper.readValue(content, javaType);
59+
}
60+
61+
@Override
62+
public <T> T readValue(byte[] content, TypeRef<T> type) throws IOException {
63+
JavaType javaType = objectMapper.getTypeFactory().constructType(type.getType());
64+
return objectMapper.readValue(content, javaType);
65+
}
66+
67+
@Override
68+
public <T> T convertValue(Object fromValue, Class<T> type) {
69+
return objectMapper.convertValue(fromValue, type);
70+
}
71+
72+
@Override
73+
public <T> T convertValue(Object fromValue, TypeRef<T> type) {
74+
JavaType javaType = objectMapper.getTypeFactory().constructType(type.getType());
75+
return objectMapper.convertValue(fromValue, javaType);
76+
}
77+
78+
@Override
79+
public String writeValueAsString(Object value) throws IOException {
80+
return objectMapper.writeValueAsString(value);
81+
}
82+
83+
@Override
84+
public byte[] writeValueAsBytes(Object value) throws IOException {
85+
return objectMapper.writeValueAsBytes(value);
86+
}
87+
88+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2026 - 2026 the original author or authors.
3+
*/
4+
5+
package io.modelcontextprotocol.json.jackson2;
6+
7+
import io.modelcontextprotocol.json.McpJsonMapper;
8+
import io.modelcontextprotocol.json.McpJsonMapperSupplier;
9+
10+
/**
11+
* A supplier of {@link McpJsonMapper} instances that uses the Jackson library for JSON
12+
* serialization and deserialization.
13+
* <p>
14+
* This implementation provides a {@link McpJsonMapper} backed by a Jackson
15+
* {@link com.fasterxml.jackson.databind.ObjectMapper}.
16+
*/
17+
public class JacksonMcpJsonMapperSupplier implements McpJsonMapperSupplier {
18+
19+
/**
20+
* Returns a new instance of {@link McpJsonMapper} that uses the Jackson library for
21+
* JSON serialization and deserialization.
22+
* <p>
23+
* The returned {@link McpJsonMapper} is backed by a new instance of
24+
* {@link com.fasterxml.jackson.databind.ObjectMapper}.
25+
* @return a new {@link McpJsonMapper} instance
26+
*/
27+
@Override
28+
public McpJsonMapper get() {
29+
return new JacksonMcpJsonMapper(new com.fasterxml.jackson.databind.ObjectMapper());
30+
}
31+
32+
}

mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson/DefaultJsonSchemaValidator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@
2424
* NetworkNT JSON Schema Validator library for validation.
2525
*
2626
* @author Christian Tzolov
27+
* @deprecated since 18.0.0, use
28+
* {@link io.modelcontextprotocol.json.schema.jackson2.DefaultJsonSchemaValidator}
29+
* instead. Will be removed in 19.0.0.
2730
*/
31+
@Deprecated(forRemoval = true, since = "18.0.0")
2832
public class DefaultJsonSchemaValidator implements JsonSchemaValidator {
2933

3034
private static final Logger logger = LoggerFactory.getLogger(DefaultJsonSchemaValidator.class);

mcp-json-jackson2/src/main/java/io/modelcontextprotocol/json/schema/jackson/JacksonJsonSchemaValidatorSupplier.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
*
1414
* @see JsonSchemaValidatorSupplier
1515
* @see JsonSchemaValidator
16+
* @deprecated since 18.0.0, use
17+
* {@link io.modelcontextprotocol.json.schema.jackson2.JacksonJsonSchemaValidatorSupplier}
18+
* instead. Will be removed in 19.0.0.
1619
*/
1720
public class JacksonJsonSchemaValidatorSupplier implements JsonSchemaValidatorSupplier {
1821

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright 2026-2026 the original author or authors.
3+
*/
4+
package io.modelcontextprotocol.json.schema.jackson2;
5+
6+
import java.util.List;
7+
import java.util.Map;
8+
import java.util.concurrent.ConcurrentHashMap;
9+
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
import com.fasterxml.jackson.core.JsonProcessingException;
14+
import com.fasterxml.jackson.databind.JsonNode;
15+
import com.fasterxml.jackson.databind.ObjectMapper;
16+
import com.networknt.schema.Error;
17+
import com.networknt.schema.Schema;
18+
import com.networknt.schema.SchemaRegistry;
19+
import com.networknt.schema.dialect.Dialects;
20+
21+
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
22+
23+
/**
24+
* Default implementation of the {@link JsonSchemaValidator} interface. This class
25+
* provides methods to validate structured content against a JSON schema. It uses the
26+
* NetworkNT JSON Schema Validator library for validation.
27+
*
28+
* @author Christian Tzolov
29+
*/
30+
public class DefaultJsonSchemaValidator implements JsonSchemaValidator {
31+
32+
private static final Logger logger = LoggerFactory.getLogger(DefaultJsonSchemaValidator.class);
33+
34+
private final ObjectMapper objectMapper;
35+
36+
private final SchemaRegistry schemaFactory;
37+
38+
// TODO: Implement a strategy to purge the cache (TTL, size limit, etc.)
39+
private final ConcurrentHashMap<String, Schema> schemaCache;
40+
41+
public DefaultJsonSchemaValidator() {
42+
this(new ObjectMapper());
43+
}
44+
45+
public DefaultJsonSchemaValidator(ObjectMapper objectMapper) {
46+
this.objectMapper = objectMapper;
47+
this.schemaFactory = SchemaRegistry.withDialect(Dialects.getDraft202012());
48+
this.schemaCache = new ConcurrentHashMap<>();
49+
}
50+
51+
@Override
52+
public ValidationResponse validate(Map<String, Object> schema, Object structuredContent) {
53+
54+
if (schema == null) {
55+
throw new IllegalArgumentException("Schema must not be null");
56+
}
57+
if (structuredContent == null) {
58+
throw new IllegalArgumentException("Structured content must not be null");
59+
}
60+
61+
try {
62+
63+
JsonNode jsonStructuredOutput = (structuredContent instanceof String)
64+
? this.objectMapper.readTree((String) structuredContent)
65+
: this.objectMapper.valueToTree(structuredContent);
66+
67+
List<Error> validationResult = this.getOrCreateJsonSchema(schema).validate(jsonStructuredOutput);
68+
69+
// Check if validation passed
70+
if (!validationResult.isEmpty()) {
71+
return ValidationResponse
72+
.asInvalid("Validation failed: structuredContent does not match tool outputSchema. "
73+
+ "Validation errors: " + validationResult);
74+
}
75+
76+
return ValidationResponse.asValid(jsonStructuredOutput.toString());
77+
78+
}
79+
catch (JsonProcessingException e) {
80+
logger.error("Failed to validate CallToolResult: Error parsing schema: {}", e);
81+
return ValidationResponse.asInvalid("Error parsing tool JSON Schema: " + e.getMessage());
82+
}
83+
catch (Exception e) {
84+
logger.error("Failed to validate CallToolResult: Unexpected error: {}", e);
85+
return ValidationResponse.asInvalid("Unexpected validation error: " + e.getMessage());
86+
}
87+
}
88+
89+
/**
90+
* Gets a cached Schema or creates and caches a new one.
91+
* @param schema the schema map to convert
92+
* @return the compiled Schema
93+
* @throws JsonProcessingException if schema processing fails
94+
*/
95+
private Schema getOrCreateJsonSchema(Map<String, Object> schema) throws JsonProcessingException {
96+
// Generate cache key based on schema content
97+
String cacheKey = this.generateCacheKey(schema);
98+
99+
// Try to get from cache first
100+
Schema cachedSchema = this.schemaCache.get(cacheKey);
101+
if (cachedSchema != null) {
102+
return cachedSchema;
103+
}
104+
105+
// Create new schema if not in cache
106+
Schema newSchema = this.createJsonSchema(schema);
107+
108+
// Cache the schema
109+
Schema existingSchema = this.schemaCache.putIfAbsent(cacheKey, newSchema);
110+
return existingSchema != null ? existingSchema : newSchema;
111+
}
112+
113+
/**
114+
* Creates a new Schema from the given schema map.
115+
* @param schema the schema map
116+
* @return the compiled Schema
117+
* @throws JsonProcessingException if schema processing fails
118+
*/
119+
private Schema createJsonSchema(Map<String, Object> schema) throws JsonProcessingException {
120+
// Convert schema map directly to JsonNode (more efficient than string
121+
// serialization)
122+
JsonNode schemaNode = this.objectMapper.valueToTree(schema);
123+
124+
// Handle case where ObjectMapper might return null (e.g., in mocked scenarios)
125+
if (schemaNode == null) {
126+
throw new JsonProcessingException("Failed to convert schema to JsonNode") {
127+
};
128+
}
129+
130+
return this.schemaFactory.getSchema(schemaNode);
131+
}
132+
133+
/**
134+
* Generates a cache key for the given schema map.
135+
* @param schema the schema map
136+
* @return a cache key string
137+
*/
138+
protected String generateCacheKey(Map<String, Object> schema) {
139+
if (schema.containsKey("$id")) {
140+
// Use the (optional) "$id" field as the cache key if present
141+
return "" + schema.get("$id");
142+
}
143+
// Fall back to schema's hash code as a simple cache key
144+
// For more sophisticated caching, could use content-based hashing
145+
return String.valueOf(schema.hashCode());
146+
}
147+
148+
/**
149+
* Clears the schema cache. Useful for testing or memory management.
150+
*/
151+
public void clearCache() {
152+
this.schemaCache.clear();
153+
}
154+
155+
/**
156+
* Returns the current size of the schema cache.
157+
* @return the number of cached schemas
158+
*/
159+
public int getCacheSize() {
160+
return this.schemaCache.size();
161+
}
162+
163+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2026 - 2026 the original author or authors.
3+
*/
4+
5+
package io.modelcontextprotocol.json.schema.jackson2;
6+
7+
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
8+
import io.modelcontextprotocol.json.schema.JsonSchemaValidatorSupplier;
9+
10+
/**
11+
* A concrete implementation of {@link JsonSchemaValidatorSupplier} that provides a
12+
* {@link JsonSchemaValidator} instance based on the Jackson library.
13+
*
14+
* @see JsonSchemaValidatorSupplier
15+
* @see JsonSchemaValidator
16+
*/
17+
public class JacksonJsonSchemaValidatorSupplier implements JsonSchemaValidatorSupplier {
18+
19+
/**
20+
* Returns a new instance of {@link JsonSchemaValidator} that uses the Jackson library
21+
* for JSON schema validation.
22+
* @return A {@link JsonSchemaValidator} instance.
23+
*/
24+
@Override
25+
public JsonSchemaValidator get() {
26+
return new DefaultJsonSchemaValidator();
27+
}
28+
29+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
io.modelcontextprotocol.json.jackson.JacksonMcpJsonMapperSupplier
1+
io.modelcontextprotocol.json.jackson2.JacksonMcpJsonMapperSupplier
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
io.modelcontextprotocol.json.schema.jackson.JacksonJsonSchemaValidatorSupplier
1+
io.modelcontextprotocol.json.schema.jackson2.JacksonJsonSchemaValidatorSupplier

0 commit comments

Comments
 (0)