概念与定义
什么是 edm 辅助序列化器?
edm 辅助序列化器(edmassistedserializer)是 apache olingo odata 框架中的一种特殊序列化器,专门设计用于在缺少完整 edm(实体数据模型)信息的情况下进行数据序列化。
核心概念
- edm(entity data model): odata 服务的元数据模型,定义了实体类型、属性、关系等
- 辅助(assisted): 表示该序列化器可以在没有完整 edm 信息的情况下工作
- 智能推断: 能够根据数据本身推断出类型和结构信息
设计目标
核心特点
1. edm 信息可选
// 可以在没有 edm 信息的情况下工作 edmassistedserializer serializer = odata.createedmassistedserializer(contenttype.application_json); // 如果有 edm 信息,会利用它进行验证和优化 serializerresult result = serializer.entitycollection( metadata, // 可选的 servicemetadata null, // 可选的 edmentitytype entitycollection, // 必需的数据 options // 序列化选项 );
2. 智能类型推断
// 自动推断数据类型 entity entity = new entity(); entity.addproperty(new property(null, "name", valuetype.primitive, "john")); entity.addproperty(new property(null, "age", valuetype.primitive, 25)); entity.addproperty(new property(null, "salary", valuetype.primitive, 50000.50)); entity.addproperty(new property(null, "isactive", valuetype.primitive, true)); // 序列化器会自动推断: // name -> string // age -> integer // salary -> double // isactive -> boolean
3. 版本感知
// 支持不同 odata 版本 list<string> versions = arrays.aslist("4.01", "4.0"); edmassistedserializer serializer = odata.createedmassistedserializer(contenttype.application_json, versions); // 根据版本自动选择合适的常量和行为 // v4.0: 使用 constantsv00 // v4.01+: 使用 constantsv01
4. 元数据级别控制
// 不同的元数据级别 edmassistedserializer nometadata = odata.createedmassistedserializer(contenttype.json_no_metadata); edmassistedserializer minimalmetadata = odata.createedmassistedserializer(contenttype.json); edmassistedserializer fullmetadata = odata.createedmassistedserializer(contenttype.json_full_metadata);
与标准序列化器的区别
对比表格
特性 | 标准序列化器 (odataserializer) | edm 辅助序列化器 (edmassistedserializer) |
---|---|---|
edm 依赖 | 必须有完整的 edm 信息 | edm 信息可选,可以没有 |
类型安全 | 编译时类型检查 | 运行时类型推断 |
性能 | 更高(有完整类型信息) | 略低(需要推断类型) |
灵活性 | 较低,结构固定 | 更高,支持动态结构 |
使用场景 | 完整的 odata 服务 | 轻量级或动态数据序列化 |
支持格式 | json, xml | 仅 json |
开发速度 | 需要先定义 edm | 可以直接开始开发 |
适用阶段 | 生产环境 | 开发、原型、集成阶段 |
使用决策流程
工作原理
序列化流程
类型推断机制
// 类型推断示例 public class typeinferenceexample { public void demonstratetypeinference() { entity entity = new entity(); // 字符串类型推断 entity.addproperty(new property(null, "stringprop", valuetype.primitive, "hello")); // 输出: "stringprop": "hello" // 数值类型推断 entity.addproperty(new property(null, "intprop", valuetype.primitive, 42)); // 输出: "intprop@odata.type": "#int32", "intprop": 42 entity.addproperty(new property(null, "doubleprop", valuetype.primitive, 3.14)); // 输出: "doubleprop@odata.type": "#double", "doubleprop": 3.14 // 布尔类型推断 entity.addproperty(new property(null, "boolprop", valuetype.primitive, true)); // 输出: "boolprop": true // 日期类型推断 entity.addproperty(new property(null, "dateprop", valuetype.primitive, calendar.getinstance())); // 输出: "dateprop@odata.type": "#datetimeoffset", "dateprop": "2025-01-15t10:30:00z" // 复杂类型推断 complexvalue address = new complexvalue(); address.getvalue().add(new property(null, "street", valuetype.primitive, "main st")); address.getvalue().add(new property(null, "city", valuetype.primitive, "seattle")); entity.addproperty(new property(null, "address", valuetype.complex, address)); // 输出: "address": { "street": "main st", "city": "seattle" } } }
详细api分析
核心接口
public interface edmassistedserializer { /** * 序列化实体集合 * @param metadata 服务元数据(可选) * @param referencedentitytype 引用的实体类型(可选) * @param entitycollection 要序列化的实体集合 * @param options 序列化选项 * @return 序列化结果 */ serializerresult entitycollection( servicemetadata metadata, edmentitytype referencedentitytype, abstractentitycollection entitycollection, edmassistedserializeroptions options ) throws serializerexception; }
实现类分析
public class edmassistedjsonserializer implements edmassistedserializer { // 关键字段 private final boolean isieee754compatible; // ieee754 兼容性 private final boolean isodatametadatanone; // 无元数据模式 private final boolean isodatametadatafull; // 完整元数据模式 private final iconstants constants; // 版本常量 // 构造函数 public edmassistedjsonserializer(final contenttype contenttype) { this.isieee754compatible = contenttypehelper.isodataieee754compatible(contenttype); this.isodatametadatanone = contenttypehelper.isodatametadatanone(contenttype); this.isodatametadatafull = contenttypehelper.isodatametadatafull(contenttype); this.constants = new constantsv00(); } // 版本感知构造函数 public edmassistedjsonserializer(final contenttype contenttype, final iconstants constants) { this.isieee754compatible = contenttypehelper.isodataieee754compatible(contenttype); this.isodatametadatanone = contenttypehelper.isodatametadatanone(contenttype); this.isodatametadatafull = contenttypehelper.isodatametadatafull(contenttype); this.constants = constants; } }
序列化选项
public class edmassistedserializeroptions { private contexturl contexturl; public static builder with() { return new builder(); } public static final class builder { private final edmassistedserializeroptions options; private builder() { options = new edmassistedserializeroptions(); } public builder contexturl(final contexturl contexturl) { options.contexturl = contexturl; return this; } public edmassistedserializeroptions build() { return options; } } }
使用场景
1. 快速原型开发
场景描述: 在项目初期,需要快速验证 odata 接口设计,但还没有完整的 edm 模型。
@restcontroller @requestmapping("/api/prototype") public class prototypecontroller { private final odata odata = odata.newinstance(); @getmapping("/users") public responseentity<string> getusers() throws serializerexception, ioexception { // 快速创建测试数据,无需预定义 edm entitycollection users = new entitycollection(); // 用户1 entity user1 = new entity(); user1.addproperty(new property(null, "id", valuetype.primitive, 1)); user1.addproperty(new property(null, "name", valuetype.primitive, "alice")); user1.addproperty(new property(null, "email", valuetype.primitive, "alice@example.com")); user1.addproperty(new property(null, "age", valuetype.primitive, 28)); user1.addproperty(new property(null, "isactive", valuetype.primitive, true)); users.getentities().add(user1); // 用户2 entity user2 = new entity(); user2.addproperty(new property(null, "id", valuetype.primitive, 2)); user2.addproperty(new property(null, "name", valuetype.primitive, "bob")); user2.addproperty(new property(null, "email", valuetype.primitive, "bob@example.com")); user2.addproperty(new property(null, "age", valuetype.primitive, 35)); user2.addproperty(new property(null, "isactive", valuetype.primitive, false)); users.getentities().add(user2); // 使用 edm 辅助序列化器 edmassistedserializer serializer = odata.createedmassistedserializer( contenttype.json_full_metadata); contexturl contexturl = contexturl.with() .entityset("users") .selectlist("id,name,email,age,isactive") .build(); edmassistedserializeroptions options = edmassistedserializeroptions.with() .contexturl(contexturl) .build(); serializerresult result = serializer.entitycollection( null, null, users, options); return responseentity.ok() .contenttype(mediatype.parsemediatype("application/json")) .body(ioutils.tostring(result.getcontent(), standardcharsets.utf_8)); } }
输出结果:
{ "@odata.context": "$metadata#users(id,name,email,age,isactive)", "value": [ { "@odata.id": null, "id@odata.type": "#int32", "id": 1, "name": "alice", "email": "alice@example.com", "age@odata.type": "#int32", "age": 28, "isactive": true }, { "@odata.id": null, "id@odata.type": "#int32", "id": 2, "name": "bob", "email": "bob@example.com", "age@odata.type": "#int32", "age": 35, "isactive": false } ] }
2. 动态数据源集成
场景描述: 从外部数据库或 api 动态获取数据,数据结构可能会变化。
@service public class dynamicdataservice { private final odata odata = odata.newinstance(); private final jdbctemplate jdbctemplate; public dynamicdataservice(jdbctemplate jdbctemplate) { this.jdbctemplate = jdbctemplate; } /** * 动态查询任意表格数据并序列化为 odata 格式 */ public string querytableasodata(string tablename, list<string> columns) throws serializerexception, ioexception { // 构建动态 sql string sql = "select " + string.join(", ", columns) + " from " + tablename; // 执行查询 list<map<string, object>> rows = jdbctemplate.queryforlist(sql); // 转换为 odata 实体集合 entitycollection entities = new entitycollection(); for (map<string, object> row : rows) { entity entity = new entity(); for (map.entry<string, object> entry : row.entryset()) { string columnname = entry.getkey(); object value = entry.getvalue(); // 动态确定值类型 valuetype valuetype = determinevaluetype(value); entity.addproperty(new property(null, columnname, valuetype, value)); } entities.getentities().add(entity); } // 使用 edm 辅助序列化器 edmassistedserializer serializer = odata.createedmassistedserializer( contenttype.application_json); contexturl contexturl = contexturl.with() .entityset(tablename) .selectlist(string.join(",", columns)) .build(); edmassistedserializeroptions options = edmassistedserializeroptions.with() .contexturl(contexturl) .build(); serializerresult result = serializer.entitycollection( null, null, entities, options); return ioutils.tostring(result.getcontent(), standardcharsets.utf_8); } private valuetype determinevaluetype(object value) { if (value == null) return valuetype.primitive; if (value instanceof string) return valuetype.primitive; if (value instanceof number) return valuetype.primitive; if (value instanceof boolean) return valuetype.primitive; if (value instanceof date || value instanceof calendar) return valuetype.primitive; if (value instanceof map) return valuetype.complex; if (value instanceof collection) return valuetype.collection_primitive; return valuetype.primitive; } }
3. 数据转换管道
场景描述: 在数据集成管道中,需要将不同格式的数据统一转换为 odata 格式。
@component public class datatransformationpipeline { private final odata odata = odata.newinstance(); /** * 将 csv 数据转换为 odata json 格式 */ public string transformcsvtoodata(string csvcontent, string entitysetname) throws serializerexception, ioexception { string[] lines = csvcontent.split("\n"); if (lines.length < 2) { throw new illegalargumentexception("csv must have at least header and one data row"); } // 解析表头 string[] headers = lines[0].split(","); entitycollection entities = new entitycollection(); // 解析数据行 for (int i = 1; i < lines.length; i++) { string[] values = lines[i].split(","); entity entity = new entity(); for (int j = 0; j < headers.length && j < values.length; j++) { string header = headers[j].trim(); string value = values[j].trim(); // 尝试推断类型并转换 object typedvalue = parsevalue(value); entity.addproperty(new property(null, header, valuetype.primitive, typedvalue)); } entities.getentities().add(entity); } return serializetoodata(entities, entitysetname); } /** * 将 json 数组转换为 odata 格式 */ public string transformjsonarraytoodata(string jsonarray, string entitysetname) throws serializerexception, ioexception { objectmapper mapper = new objectmapper(); try { list<map<string, object>> datalist = mapper.readvalue(jsonarray, new typereference<list<map<string, object>>>() {}); entitycollection entities = new entitycollection(); for (map<string, object> datamap : datalist) { entity entity = new entity(); for (map.entry<string, object> entry : datamap.entryset()) { string key = entry.getkey(); object value = entry.getvalue(); valuetype valuetype = determinevaluetype(value); entity.addproperty(new property(null, key, valuetype, value)); } entities.getentities().add(entity); } return serializetoodata(entities, entitysetname); } catch (exception e) { throw new runtimeexception("failed to parse json array", e); } } private string serializetoodata(entitycollection entities, string entitysetname) throws serializerexception, ioexception { // 支持多版本 list<string> versions = arrays.aslist("4.01", "4.0"); edmassistedserializer serializer = odata.createedmassistedserializer( contenttype.application_json, versions); contexturl contexturl = contexturl.with() .entityset(entitysetname) .build(); edmassistedserializeroptions options = edmassistedserializeroptions.with() .contexturl(contexturl) .build(); serializerresult result = serializer.entitycollection( null, null, entities, options); return ioutils.tostring(result.getcontent(), standardcharsets.utf_8); } private object parsevalue(string value) { // 尝试解析为不同类型 if (value.isempty() || "null".equalsignorecase(value)) { return null; } // 布尔值 if ("true".equalsignorecase(value) || "false".equalsignorecase(value)) { return boolean.parseboolean(value); } // 整数 try { return integer.parseint(value); } catch (numberformatexception e) { // 不是整数,继续尝试其他类型 } // 浮点数 try { return double.parsedouble(value); } catch (numberformatexception e) { // 不是浮点数,继续尝试其他类型 } // 日期(简单格式) try { simpledateformat dateformat = new simpledateformat("yyyy-mm-dd"); return dateformat.parse(value); } catch (parseexception e) { // 不是日期格式 } // 默认作为字符串 return value; } private valuetype determinevaluetype(object value) { if (value == null) return valuetype.primitive; if (value instanceof string) return valuetype.primitive; if (value instanceof number) return valuetype.primitive; if (value instanceof boolean) return valuetype.primitive; if (value instanceof date) return valuetype.primitive; if (value instanceof map) return valuetype.complex; if (value instanceof list) return valuetype.collection_primitive; return valuetype.primitive; } }
4. 微服务数据聚合
场景描述: 从多个微服务聚合数据,各服务的数据格式可能不同。
@restcontroller @requestmapping("/api/aggregation") public class dataaggregationcontroller { private final odata odata = odata.newinstance(); @autowired private userservice userservice; @autowired private orderservice orderservice; @autowired private productservice productservice; /** * 聚合用户、订单和产品数据 */ @getmapping("/dashboard") public responseentity<string> getdashboarddata() throws serializerexception, ioexception { entitycollection dashboarddata = new entitycollection(); // 聚合用户数据 list<user> users = userservice.getactiveusers(); for (user user : users) { entity userentity = new entity(); userentity.addproperty(new property(null, "type", valuetype.primitive, "user")); userentity.addproperty(new property(null, "id", valuetype.primitive, user.getid())); userentity.addproperty(new property(null, "name", valuetype.primitive, user.getname())); userentity.addproperty(new property(null, "email", valuetype.primitive, user.getemail())); userentity.addproperty(new property(null, "lastlogin", valuetype.primitive, user.getlastlogin())); // 动态添加用户统计信息 map<string, object> stats = userservice.getuserstats(user.getid()); for (map.entry<string, object> stat : stats.entryset()) { userentity.addproperty(new property(null, "stats_" + stat.getkey(), valuetype.primitive, stat.getvalue())); } dashboarddata.getentities().add(userentity); } // 聚合订单数据 list<order> recentorders = orderservice.getrecentorders(30); for (order order : recentorders) { entity orderentity = new entity(); orderentity.addproperty(new property(null, "type", valuetype.primitive, "order")); orderentity.addproperty(new property(null, "id", valuetype.primitive, order.getid())); orderentity.addproperty(new property(null, "userid", valuetype.primitive, order.getuserid())); orderentity.addproperty(new property(null, "amount", valuetype.primitive, order.getamount())); orderentity.addproperty(new property(null, "status", valuetype.primitive, order.getstatus())); orderentity.addproperty(new property(null, "createdat", valuetype.primitive, order.getcreatedat())); dashboarddata.getentities().add(orderentity); } // 聚合产品数据(动态属性) list<map<string, object>> productdata = productservice.getproductanalytics(); for (map<string, object> product : productdata) { entity productentity = new entity(); productentity.addproperty(new property(null, "type", valuetype.primitive, "product")); // 动态添加所有产品属性 for (map.entry<string, object> entry : product.entryset()) { valuetype valuetype = determinevaluetype(entry.getvalue()); productentity.addproperty(new property(null, entry.getkey(), valuetype, entry.getvalue())); } dashboarddata.getentities().add(productentity); } // 使用 edm 辅助序列化器序列化混合数据 edmassistedserializer serializer = odata.createedmassistedserializer( contenttype.application_json); contexturl contexturl = contexturl.with() .entityset("dashboarddata") .build(); edmassistedserializeroptions options = edmassistedserializeroptions.with() .contexturl(contexturl) .build(); serializerresult result = serializer.entitycollection( null, null, dashboarddata, options); string jsonoutput = ioutils.tostring(result.getcontent(), standardcharsets.utf_8); return responseentity.ok() .contenttype(mediatype.application_json) .body(jsonoutput); } private valuetype determinevaluetype(object value) { if (value == null) return valuetype.primitive; if (value instanceof string) return valuetype.primitive; if (value instanceof number) return valuetype.primitive; if (value instanceof boolean) return valuetype.primitive; if (value instanceof date || value instanceof calendar) return valuetype.primitive; if (value instanceof map) return valuetype.complex; if (value instanceof collection) return valuetype.collection_primitive; return valuetype.primitive; } }
代码案例
案例1: 基础使用
public class basicusageexample { public void basicexample() throws serializerexception, ioexception { odata odata = odata.newinstance(); // 1. 创建 edm 辅助序列化器 edmassistedserializer serializer = odata.createedmassistedserializer( contenttype.application_json); // 2. 创建数据 entity person = new entity(); person.addproperty(new property(null, "firstname", valuetype.primitive, "john")); person.addproperty(new property(null, "lastname", valuetype.primitive, "doe")); person.addproperty(new property(null, "age", valuetype.primitive, 30)); entitycollection people = new entitycollection(); people.getentities().add(person); // 3. 序列化 serializerresult result = serializer.entitycollection( null, null, people, null); // 4. 获取结果 string json = ioutils.tostring(result.getcontent(), standardcharsets.utf_8); system.out.println(json); } }
案例2: 复杂类型处理
public class complextypeexample { public void complextypeexample() throws serializerexception, ioexception { odata odata = odata.newinstance(); edmassistedserializer serializer = odata.createedmassistedserializer( contenttype.json_full_metadata); // 创建包含复杂类型的实体 entity employee = new entity(); employee.addproperty(new property(null, "employeeid", valuetype.primitive, 1001)); employee.addproperty(new property(null, "name", valuetype.primitive, "alice johnson")); // 创建地址复杂类型 complexvalue address = new complexvalue(); address.getvalue().add(new property(null, "street", valuetype.primitive, "123 main st")); address.getvalue().add(new property(null, "city", valuetype.primitive, "seattle")); address.getvalue().add(new property(null, "state", valuetype.primitive, "wa")); address.getvalue().add(new property(null, "zipcode", valuetype.primitive, "98101")); employee.addproperty(new property(null, "address", valuetype.complex, address)); // 创建联系方式复杂类型 complexvalue contact = new complexvalue(); contact.getvalue().add(new property(null, "email", valuetype.primitive, "alice@company.com")); contact.getvalue().add(new property(null, "phone", valuetype.primitive, "+1-555-0123")); employee.addproperty(new property(null, "contact", valuetype.complex, contact)); // 创建技能集合 list<string> skills = arrays.aslist("java", "spring", "odata", "sql"); employee.addproperty(new property(null, "skills", valuetype.collection_primitive, skills)); entitycollection employees = new entitycollection(); employees.getentities().add(employee); // 设置上下文 url contexturl contexturl = contexturl.with() .entityset("employees") .build(); edmassistedserializeroptions options = edmassistedserializeroptions.with() .contexturl(contexturl) .build(); serializerresult result = serializer.entitycollection( null, null, employees, options); string json = ioutils.tostring(result.getcontent(), standardcharsets.utf_8); system.out.println("complex type example output:"); system.out.println(json); } }
输出结果:
{ "@odata.context": "$metadata#employees", "value": [ { "@odata.id": null, "employeeid@odata.type": "#int32", "employeeid": 1001, "name": "alice johnson", "address": { "street": "123 main st", "city": "seattle", "state": "wa", "zipcode": "98101" }, "contact": { "email": "alice@company.com", "phone": "+1-555-0123" }, "skills@odata.type": "#collection(string)", "skills": ["java", "spring", "odata", "sql"] } ] }
案例3: 版本差异处理
public class versionhandlingexample { public void compareversions() throws serializerexception, ioexception { odata odata = odata.newinstance(); // 创建测试数据 entity product = new entity(); product.addproperty(new property(null, "productid", valuetype.primitive, 1)); product.addproperty(new property(null, "name", valuetype.primitive, "laptop")); product.addproperty(new property(null, "price", valuetype.primitive, 999.99)); product.addproperty(new property(null, "instock", valuetype.primitive, true)); entitycollection products = new entitycollection(); products.getentities().add(product); // v4.0 序列化 list<string> versionsv40 = arrays.aslist("4.0"); edmassistedserializer serializerv40 = odata.createedmassistedserializer( contenttype.application_json, versionsv40); serializerresult resultv40 = serializerv40.entitycollection( null, null, products, null); string jsonv40 = ioutils.tostring(resultv40.getcontent(), standardcharsets.utf_8); system.out.println("odata v4.0 output:"); system.out.println(jsonv40); // v4.01 序列化 list<string> versionsv401 = arrays.aslist("4.01"); edmassistedserializer serializerv401 = odata.createedmassistedserializer( contenttype.application_json, versionsv401); serializerresult resultv401 = serializerv401.entitycollection( null, null, products, null); string jsonv401 = ioutils.tostring(resultv401.getcontent(), standardcharsets.utf_8); system.out.println("\nodata v4.01 output:"); system.out.println(jsonv401); } }
案例4: 元数据级别对比
public class metadatalevelexample { public void comparemetadatalevels() throws serializerexception, ioexception { odata odata = odata.newinstance(); // 创建测试数据 entity order = new entity(); order.addproperty(new property(null, "orderid", valuetype.primitive, 12345)); order.addproperty(new property(null, "customername", valuetype.primitive, "john smith")); order.addproperty(new property(null, "orderdate", valuetype.primitive, calendar.getinstance())); order.addproperty(new property(null, "totalamount", valuetype.primitive, 129.99)); entitycollection orders = new entitycollection(); orders.getentities().add(order); contexturl contexturl = contexturl.with() .entityset("orders") .build(); edmassistedserializeroptions options = edmassistedserializeroptions.with() .contexturl(contexturl) .build(); // 1. 无元数据 edmassistedserializer nometadata = odata.createedmassistedserializer( contenttype.json_no_metadata); serializerresult resultnometa = nometadata.entitycollection( null, null, orders, options); string jsonnometa = ioutils.tostring(resultnometa.getcontent(), standardcharsets.utf_8); system.out.println("no metadata:"); system.out.println(jsonnometa); // 2. 最小元数据 edmassistedserializer minimalmetadata = odata.createedmassistedserializer( contenttype.json); serializerresult resultminimal = minimalmetadata.entitycollection( null, null, orders, options); string jsonminimal = ioutils.tostring(resultminimal.getcontent(), standardcharsets.utf_8); system.out.println("\nminimal metadata:"); system.out.println(jsonminimal); // 3. 完整元数据 edmassistedserializer fullmetadata = odata.createedmassistedserializer( contenttype.json_full_metadata); serializerresult resultfull = fullmetadata.entitycollection( null, null, orders, options); string jsonfull = ioutils.tostring(resultfull.getcontent(), standardcharsets.utf_8); system.out.println("\nfull metadata:"); system.out.println(jsonfull); } }
案例5: 错误处理和边界情况
public class errorhandlingexample { public void demonstrateerrorhandling() { odata odata = odata.newinstance(); // 1. 不支持的内容类型 try { edmassistedserializer serializer = odata.createedmassistedserializer( contenttype.application_xml); // 不支持 xml } catch (serializerexception e) { system.out.println("expected error - unsupported format: " + e.getmessage()); } // 2. 空数据处理 try { edmassistedserializer serializer = odata.createedmassistedserializer( contenttype.application_json); entitycollection emptycollection = new entitycollection(); serializerresult result = serializer.entitycollection( null, null, emptycollection, null); string json = ioutils.tostring(result.getcontent(), standardcharsets.utf_8); system.out.println("empty collection result: " + json); } catch (exception e) { system.out.println("error handling empty collection: " + e.getmessage()); } // 3. 空值属性处理 try { edmassistedserializer serializer = odata.createedmassistedserializer( contenttype.application_json); entity entitywithnulls = new entity(); entitywithnulls.addproperty(new property(null, "name", valuetype.primitive, "test")); entitywithnulls.addproperty(new property(null, "nullvalue", valuetype.primitive, null)); entitywithnulls.addproperty(new property(null, "emptystring", valuetype.primitive, "")); entitycollection collection = new entitycollection(); collection.getentities().add(entitywithnulls); serializerresult result = serializer.entitycollection( null, null, collection, null); string json = ioutils.tostring(result.getcontent(), standardcharsets.utf_8); system.out.println("null values handling: " + json); } catch (exception e) { system.out.println("error handling null values: " + e.getmessage()); } } }
最佳实践
1. 选择合适的元数据级别
public class metadatabestpractices { // 生产环境 - 使用最小元数据以减少带宽 public edmassistedserializer createproductionserializer() throws serializerexception { odata odata = odata.newinstance(); return odata.createedmassistedserializer(contenttype.json); } // 开发和调试 - 使用完整元数据便于调试 public edmassistedserializer createdevelopmentserializer() throws serializerexception { odata odata = odata.newinstance(); return odata.createedmassistedserializer(contenttype.json_full_metadata); } // 性能敏感场景 - 使用无元数据 public edmassistedserializer createperformanceserializer() throws serializerexception { odata odata = odata.newinstance(); return odata.createedmassistedserializer(contenttype.json_no_metadata); } }
2. 版本管理策略
public class versionmanagementbestpractices { private final odata odata = odata.newinstance(); // 支持多版本的通用方法 public edmassistedserializer createversionawareserializer( contenttype contenttype, string clientversion) throws serializerexception { list<string> supportedversions = determinesupportedversions(clientversion); return odata.createedmassistedserializer(contenttype, supportedversions); } private list<string> determinesupportedversions(string clientversion) { list<string> versions = new arraylist<>(); if (clientversion != null && clientversion.startswith("4.01")) { versions.add("4.01"); versions.add("4.0"); // 向后兼容 } else { versions.add("4.0"); } return versions; } }
3. 性能优化
public class performanceoptimization { // 序列化器复用 private final map<string, edmassistedserializer> serializercache = new concurrenthashmap<>(); private final odata odata = odata.newinstance(); public edmassistedserializer getcachedserializer(contenttype contenttype, list<string> versions) throws serializerexception { string key = contenttype.tocontenttypestring() + "_" + (versions != null ? string.join(",", versions) : "default"); return serializercache.computeifabsent(key, k -> { try { return versions != null && !versions.isempty() ? odata.createedmassistedserializer(contenttype, versions) : odata.createedmassistedserializer(contenttype); } catch (serializerexception e) { throw new runtimeexception("failed to create serializer", e); } }); } // 批量序列化优化 public string serializelargedataset(list<entity> entities, string entitysetname) throws serializerexception, ioexception { edmassistedserializer serializer = getcachedserializer( contenttype.json_no_metadata, null); // 分批处理大数据集 int batchsize = 1000; stringbuilder result = new stringbuilder(); result.append("{\"value\":["); for (int i = 0; i < entities.size(); i += batchsize) { int endindex = math.min(i + batchsize, entities.size()); list<entity> batch = entities.sublist(i, endindex); entitycollection batchcollection = new entitycollection(); batchcollection.getentities().addall(batch); serializerresult batchresult = serializer.entitycollection( null, null, batchcollection, null); string batchjson = ioutils.tostring(batchresult.getcontent(), standardcharsets.utf_8); // 提取值数组部分 if (i > 0) result.append(","); // 处理批次json... } result.append("]}"); return result.tostring(); } }
4. 类型安全
public class typesafetybestpractices { // 使用类型安全的属性创建器 public static class propertybuilder { public static property createstringproperty(string name, string value) { return new property(null, name, valuetype.primitive, value); } public static property createintproperty(string name, integer value) { return new property(null, name, valuetype.primitive, value); } public static property createdoubleproperty(string name, double value) { return new property(null, name, valuetype.primitive, value); } public static property createbooleanproperty(string name, boolean value) { return new property(null, name, valuetype.primitive, value); } public static property createdateproperty(string name, date value) { return new property(null, name, valuetype.primitive, value); } public static property createcomplexproperty(string name, complexvalue value) { return new property(null, name, valuetype.complex, value); } public static property createcollectionproperty(string name, collection<?> value) { return new property(null, name, valuetype.collection_primitive, value); } } // 使用示例 public entity createtypesafeentity() { entity entity = new entity(); entity.addproperty(propertybuilder.createstringproperty("name", "john doe")); entity.addproperty(propertybuilder.createintproperty("age", 30)); entity.addproperty(propertybuilder.createdoubleproperty("salary", 75000.0)); entity.addproperty(propertybuilder.createbooleanproperty("isactive", true)); entity.addproperty(propertybuilder.createdateproperty("hiredate", new date())); return entity; } }
常见问题
q1: edm 辅助序列化器与标准序列化器的性能差异有多大?
a: 在大多数场景下,性能差异在 10-20% 之间。主要开销来自运行时类型推断。
public class performancecomparison { @test public void compareperformance() throws exception { // 准备测试数据 entitycollection testdata = createlargetestdataset(10000); // 测试标准序列化器 long starttime = system.currenttimemillis(); odataserializer standardserializer = odata.createserializer(contenttype.application_json); // ... 序列化逻辑 long standardtime = system.currenttimemillis() - starttime; // 测试 edm 辅助序列化器 starttime = system.currenttimemillis(); edmassistedserializer assistedserializer = odata.createedmassistedserializer( contenttype.application_json); // ... 序列化逻辑 long assistedtime = system.currenttimemillis() - starttime; system.out.println("standard serializer: " + standardtime + "ms"); system.out.println("assisted serializer: " + assistedtime + "ms"); system.out.println("performance ratio: " + ((double)assistedtime / standardtime)); } }
q2: 如何处理循环引用?
a: edm 辅助序列化器不会自动处理循环引用,需要在创建数据时避免。
public class circularreferencehandling { public entity createentitywithoutcircularref(user user, set<string> processedids) { if (processedids.contains(user.getid())) { // 创建引用实体,避免循环 entity refentity = new entity(); refentity.addproperty(propertybuilder.createstringproperty("id", user.getid())); refentity.addproperty(propertybuilder.createstringproperty("name", user.getname())); return refentity; } processedids.add(user.getid()); entity entity = new entity(); entity.addproperty(propertybuilder.createstringproperty("id", user.getid())); entity.addproperty(propertybuilder.createstringproperty("name", user.getname())); // 安全地添加关联实体 if (user.getmanager() != null) { entity managerentity = createentitywithoutcircularref(user.getmanager(), processedids); entity.addproperty(new property(null, "manager", valuetype.complex, convertentitytocomplexvalue(managerentity))); } return entity; } }
q3: 如何优化大数据集的序列化?
a: 使用流式处理和分批序列化:
public class largedatasetoptimization { public void streamlargedataset(iterator<entity> entityiterator, outputstream outputstream) throws ioexception, serializerexception { jsongenerator jsongenerator = new jsonfactory().creategenerator(outputstream); jsongenerator.writestartobject(); jsongenerator.writearrayfieldstart("value"); edmassistedserializer serializer = odata.createedmassistedserializer( contenttype.json_no_metadata); while (entityiterator.hasnext()) { entity entity = entityiterator.next(); entitycollection singleentitycollection = new entitycollection(); singleentitycollection.getentities().add(entity); serializerresult result = serializer.entitycollection( null, null, singleentitycollection, null); // 直接写入流,避免内存积累 ioutils.copy(result.getcontent(), outputstream); if (entityiterator.hasnext()) { jsongenerator.writeraw(","); } } jsongenerator.writeendarray(); jsongenerator.writeendobject(); jsongenerator.close(); } }
总结
edm 辅助序列化器的价值
- 开发效率: 无需预先定义完整的 edm 模型,可以快速开始开发
- 灵活性: 能够处理动态结构的数据,适应数据模型的变化
- 集成友好: 便于与外部系统集成,处理格式不统一的数据
- 原型开发: 适合快速原型开发和概念验证
适用场景总结
场景 | 适用性 | 推荐理由 |
---|---|---|
快速原型开发 | ⭐⭐⭐⭐⭐ | 无需预定义 edm,快速验证想法 |
动态数据源 | ⭐⭐⭐⭐⭐ | 能够处理结构变化的数据 |
数据集成 | ⭐⭐⭐⭐ | 统一不同格式的数据输出 |
微服务聚合 | ⭐⭐⭐⭐ | 整合多个服务的异构数据 |
生产环境 | ⭐⭐⭐ | 性能略低,但提供更大灵活性 |
最终建议
- 开发阶段: 优先使用 edm 辅助序列化器,加快开发速度
- 生产环境: 如果数据结构稳定,考虑迁移到标准序列化器以获得更好性能
- 混合使用: 对于不同的接口,可以根据需求选择不同的序列化器
- 渐进式采用: 从 edm 辅助序列化器开始,逐步完善 edm 模型
edm 辅助序列化器是 apache olingo odata 框架中的一个强大工具,它在保持 odata 协议兼容性的同时,提供了极大的开发灵活性。通过合理使用,可以显著提高开发效率并简化数据集成工作。
到此这篇关于olingo分析和实践之edm 辅助序列化器详解(最佳实践)的文章就介绍到这了,更多相关olingo edm 辅助序列化器内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论