Schema Value Object

Schema Value Object

Author

Olivier Brand (obrand@yahoo.com)
08/23/2001

Context

Value Objects must include validation code in order to optimize network traffic and XML features for B2B exchanges.

Problems

While implementing a three tier application using J2EE Core Patterns, a usual design will involve at least some Value Objects, some Session Facades, a few
Entity Beans and Data Access Objects for the underlying persistence logic.

A Value Object is the representation of a business data. Therefore it contains attributes and associated business methods.
A Value Object can be initialized by the Enterprise Java Bean layer (in the case of reads) or by the Client (in the case of creations or updates).
Usually the Value Object does not need to be validated when being created in the Enterprise layer since we assume that the data has already been
constrained by the persistent store.

A problem occurs when creating or updating these Value Objects (mutable Value Objects) in the Client layer.
For instance an attribute representing the email address of a customer in the Value Object can be tied to a specific column in a database with additional
constraints such as the length of the column and its format following a specific pattern (regular expression driven, ...).
Now the developer needs to make a decision where to add the validation code on this field.

The most common solution is to rely on the underlying datastore which will reject the insert or update if a field does not conform to a specific constraint.

The problem of relying on the datastore to check the data constraints is expensive in term of network overhead.
Another problem is that the implementation is more complex since the eventual thrown exceptions need to traverse multiple layers and be interpreted by the
client layer.

B2B data exchange must be realized through the HTTP protocol to overcome firewall restrictions. Standards such as SOAP, eBxml, ... are already defined.
Multiple implementations of these standards allow to wrap Enterprise Beans in a Web Service. Since the Enterprise Bean layer plays the role of a Value
Object Factory, the reulting data needs to be transformed at one point as XML to be encapsulated into SOAP or eBxml packets.

Forces

     The validation of a Value Object is done early on, avoiding Network overheads (similar to the role of Javascript for form validation in web
     applications)
     Simplify the three tier layer in term of exception handling
     Can rely on W3C specifications such as XML Schemas (or DTDs) for documenting and generating (see solution) data constraints.
     XML aware Value Objects can be easily included in B2B exchanges

Solution

Use an existing XML framework to express data constraints and automate the process to unmarshal XML documents to Java Objects and to
marshal Java Objects to XML documents.

There are many XML frameworks available. Some are relying on DTDs, others are relying on the newest XML Schema (aka XSD) specifications.
I chose to rely on the XML Schema specification in order to express the Value Object constraints.XML Schemas are defined in XML (as opposed to
DTDs), therefore can be created using any XML aware tools, documentation can also be generated using XSL transforms (output HTML, ....).
XML Schemas are "object oriented friendly" since they allow for complex types creation and extension.

The framework of choice used for implementing this pattern is Castor from Exolab. This framework is on its way to support the final W3C specification, but
it showed in any projects that its Schema support is enough for implementing this pattern. This framework is also Open Source.

The main idea is to write an XML schema corresponding to the structure of the final Value Object (in term of attributes and types), and add the constraints
as defined in the database (length, format, .....). Some constraints such as uniqueness cannot be expressed, but typically, you want the underlying database to
reject the record if such constraint is violated.

Then you can use the Castor source generator class to generate the Java classes associated with the XSD Schema. Each complex type is sually defined as a
Class. Each element, attributes are defined as properties (class variable) and corresponding setter/getter methods are automatically generated.

Relying on a source generator prevents coding complex validation rules in a language that cannot be understand by non Java developers. For instance a
Database modeler and an Architect (or Senior Developer) can be involved early on in order to define those schemas. This will be the starting point for the
DDL and the Schema Value Objects generations. This is a nice approach to bring 2 different teams together on a design and implementation phases.

Then the Schema Value Objects need to be created. At this stage there are 2 possible choices:

     The Schema Value Object extends the generated Java class from the XSD schema.
     The Schema Value Object encapsulates (wraps) the generated Java class from the XSD schema.

I prefer the second solution for 2 reasons:

     The Castor framework (or any other Schema aware framework generators) defines new types which correspond to the richer XSD Schema definition
     (compared to Java types). Therefore, you might want to hide these "proprietary" classes allowing later on (if needed) to replace the Java Schema
     generator with another one (for instance, when Javasoft will provide a Schema module for its JAXB framework).
     You might want to validate field by field (when each setter is being called) and add some dirty flag support in the same methods. Wrapping the
     generated setters with your own setters make then more sense.

When generating the Java classes from the XSD Schema using Castor, special classes called Descriptors are created.
These classes are handling the validation part (the constraints defined in the XML Schema are showing in this classes).

Do we want to validate field by field or the entire document ? Once again this is an implementationd ecision mostly driven by the client's implementation.

In my implementations, we decided to validate field by field (the validation is done in each setters).

To perform a field level validation, the Castor XML API offers a class to perform validation at the field level (as opposed as the entire document):

     FieldValidator.

I highly encourage you to look at castor.exolab.org in order to get familiar with the possibility of the product.

The second part of the pattern is trivial since any Schema (or DTDs) aware code generator, Castor included, include marshaling and unmarshaling facilities.
These methods allow to transform Java to XML and XML to Java.

Castor offers 2 classes to perform such transformations: Marshaller and Unmarshaller.

The Marshaller class can transform a Java object to XML. Some methods allow to marshal the object directly in a W3X DOM Node object.
This method is highly optimized when dealing with SOAP where you want to include a fragment (therefore the generated Node) in a SOAP enveloppe.
This method is also preffered when dealing with XSL (in frameworks like Apache Cocoon, ....) since the DOM tree is already built.
This method also works with the W3C SAX API.

The Unmarshaller class can transform any XML sources to the Castor generated Java object.

One of my projects included this pattern and was successfully implemented using the Apache SOAP framework with a WSDL extension we had to write.
WSDL is an XML document containing the definition of the operations exposed as web services. Any complex types are referred to an XML Schema.
This is one of the reason why this pattern perfectly applies to B2B exchanges by bringing the J2EE and B2B worlds together.

Consequences

     Takes advantage of the Value Object pattern
     Therefore it reduces network traffic.

     Uses W3C standards to express data constraints
     Schemas or DTDs can be understood by non java developper and is the common ground for B2B exchanges (see WSDL, SOAP, UDDI, ...)

     Allows for automated code generation
     Once the XSD Schema written, a Java Binding framework like Castor, can be used to generate the Java classes.

     Includes an XML framework to serialize/deserialize Java object to and from XML.
     This fits perfectly in the Web Services world. This can also be used in Web Applications driven by JSPs and XSLT processing.

Related patterns

     Value Object (Sun)
     Proxy (GoF)

Links

     SUN patterns: http://developer.java.sun.com/developer/restricted/patterns
     GoF Patterns: http://www.hillside.net/patterns/DPBook/DPBook.html
     Castor XML: http://castor.exolab.org
2 replies in this thread Reply
Read more Schema Value Object
Posted By: Olivier Brand on August 25, 2001 in response to this message.
This pattern could (and should) be renamed: Schema Data Object.
This approach applies to a lot of scenarios and schemas are a good complement to add constraints to languages.
The Value Object could be one implementation of this pattern.
0 replies in this thread Reply
Read more Schema Value Object - Options
Posted By: Earl Bingham on August 31, 2001 in response to this message.

At sourceforge.net there is a project called jvalid that was started last year that does validation with XML Schemas.

http://sourceforge.net/projects/jvalid/

Also, there is a XSLT Stylesheet called Schematron that is designed to allow validation of XML Documents to be done with a definition of the validation in XML.

http://www.ascc.net/xml/resource/schematron/schematron.html

I have started a project in sourceforge.net to build some J2EE components that can be re-used that leverage the Schematron Stylesheet.
<think>我们面对的问题:调用远端MCP工具时,参数schema定义为object,但实际传入字符串,导致JSON校验错误。 原因分析:当MCP工具期望的参数类型是对象(object)时,调用方传入了一个字符串(string)。这通常是因为传入的字符串不是有效的JSON格式,或者即使字符串表示一个JSON对象,但未正确解析为对象。 解决方案思路: 1. 确保传入参数是对象(object)而不是字符串(string)。如果工具期望一个对象,那么调用时应该传递一个JavaScript对象(在JSON中就是键值对结构)。 2. 如果调用方只有字符串,并且该字符串是JSON格式的,那么需要在调用前将其解析为对象。 3. 检查MCP工具的参数定义,确保它正确地声明了参数类型为object,并且传入的数据结构匹配该定义。 具体步骤: 步骤1:检查传入参数的数据类型 在调用MCP工具之前,确保传入的参数是一个对象,而不是字符串。如果是字符串,尝试将其解析为对象。 例如,在JavaScript环境中,可以使用JSON.parse()来将字符串转换为对象: ```javascript let params; try { params = JSON.parse(inputString); } catch (e) { // 处理解析错误 } ``` 步骤2:验证参数是否符合schema 使用JSON Schema验证库(如ajv)来验证参数对象是否符合工具定义的schema。 步骤3:修正MCP工具定义 如果工具定义的参数类型为object,但实际期望的是字符串,那么需要修正MCP工具的定义。但根据问题描述,是参数类型不匹配,所以这里我们假设工具定义是正确的,问题出在调用方传递了错误类型。 步骤4:在create_agent-react中处理参数 在create_agent-react框架中,调用MCP工具之前,对参数进行预处理。确保传入的参数类型与工具定义的schema匹配。 示例代码(假设在调用MCP工具之前有参数处理逻辑): ```javascript function prepareParameters(toolDef, parameters) { // 如果工具定义的参数schema类型是object,而传入的是字符串,尝试解析 if (toolDef.parameters && toolDef.parameters.type === 'object' && typeof parameters === 'string') { try { parameters = JSON.parse(parameters); } catch (e) { throw new Error('参数不是有效的JSON字符串'); } } return parameters; } ``` 然后在调用MCP工具的地方: ```javascript const preparedParams = prepareParameters(toolDefinition, originalParams); // 然后使用preparedParams调用工具 ``` 步骤5:错误处理 在解析或验证失败时,应该给出明确的错误信息,以便调试。 步骤6:考虑其他类型 同样地,如果工具定义的其他类型(如array、number等)而传入的是字符串,也需要做相应的转换和验证。 总结:关键在于确保传入的参数类型与工具定义的schema类型一致。如果传入的是字符串,但需要的是对象,且字符串是JSON格式,则解析它;如果不是,则报错。 相关问题: 1. 如何避免在调用MCP工具时出现参数类型不匹配的问题? 2. 在create_agent-react中,如何动态处理不同类型的参数? 3. MCP工具的参数schema定义有哪些类型?如何正确使用它们?</think>### 参数类型不匹配问题的解决方案 当使用`create_agent-react`调用远端MCP工具时,因参数schema定义为`object`但传入字符串导致JSON校验错误,可通过以下步骤解决: #### 1. **参数类型校验与转换** 在调用工具前添加参数预处理层,确保数据类型匹配: ```javascript function preprocessParams(toolSchema, rawParams) { // 当schema要求object但传入字符串时尝试解析 if (toolSchema.type === 'object' && typeof rawParams === 'string') { try { return JSON.parse(rawParams); // 转换为对象 } catch (e) { throw new Error(`参数解析失败: ${e.message}`); } } return rawParams; } // 调用示例 const processedParams = preprocessParams(tool.schema, inputParams); await invokeMCPTool(processedParams); ``` #### 2. **Schema定义规范检查** 确保MCP工具的schema定义符合JSON Schema标准: ```json // 正确示例 { "type": "object", "properties": { "name": {"type": "string"}, "config": {"type": "object"} // 嵌套对象需明确定义 } } ``` 避免模糊定义如`{"type": "object"}`,应明确指定`properties`约束[^1]。 #### 3. **工具调用端类型声明** 在Agent创建时声明参数类型,强制类型检查: ```javascript create_agent({ tools: [{ name: "mcp_tool", parameters: { config: { type: "object", // 明确声明类型 description: "必须为JSON对象" } } }] }) ``` #### 4. **错误处理机制** 添加结构化错误反馈: ```javascript try { await agent.executeTool("mcp_tool", params); } catch (error) { if (error.isValidationError) { console.error("类型错误详情:", error.details); // 返回标准格式错误:{"code": "INVALID_TYPE", "expected": "object", "actual": "string"} } } ``` #### 5. **文档与测试建议** - 在工具描述中明确参数要求:`## 注意: config参数必须为JSON对象,非字符串` - 添加单元测试验证类型边界: ```javascript test("应拒绝字符串参数", () => { expect(() => invokeTool("{'key':'value'}")).toThrow(TypeError); }); ``` > **根本原因分析**:该错误通常发生在未严格区分JSON字符串与JS对象时。MCP工具期望接收已解析的对象结构(如`{key: value}`),但调用方可能直接传递了JSON字符串(如`'{"key":"value"}'`)[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值