Java Jackson序列化/反序列化:动态属性和字段
我使用SpringMVC来驱动当前正在使用的应用程序的API。API响应的序列化是通过Jackson的Java Jackson序列化/反序列化:动态属性和字段,java,json,spring,spring-mvc,jackson,Java,Json,Spring,Spring Mvc,Jackson,我使用SpringMVC来驱动当前正在使用的应用程序的API。API响应的序列化是通过Jackson的ObjectMapper完成的。我面临以下情况,我们正在扩展许多对象以支持UserDefinedFields(UDF),如下面的摘要UserDefinedResponse所示。作为一个SaaS解决方案,多个客户端具有不同的配置,这些配置存储在数据库中,用于其自定义字段 这个问题的目标是能够用他们的UDF数据对每个客户做出响应。这需要 动态重命名字段customString1,customStri
ObjectMapper
完成的。我面临以下情况,我们正在扩展许多对象以支持UserDefinedFields(UDF),如下面的摘要UserDefinedResponse
所示。作为一个SaaS解决方案,多个客户端具有不同的配置,这些配置存储在数据库中,用于其自定义字段
这个问题的目标是能够用他们的UDF数据对每个客户做出响应。这需要
customString1
,customString2
。。。到相应的UDF标签public abstract class UserDefinedResponse {
public String customString1;
public String customString2;
public String customString3;
public String customString4;
}
以及扩展UserDefinedResponse
对象的产品的响应
public class Product extends UserDefinedResponse {
public long id;
public String name;
public float price;
}
最后,假设客户机
=customString1
“供应商”
=customString2
“仓库”
产品
,应产生类似的结果:
{
"id" : 1234,
"name" : "MacBook Air",
"price" : 1299,
"supplier" : "Apple",
"warehouse" : "New York warehouse"
}
您考虑过将Map作为响应返回吗?或者是响应的一部分,比如response.getUDF().get(“customStringX”)?这将为您在将来节省一些可能的麻烦,例如:1000万并发用户意味着您的VM中有1000万个类。我认为您可以借助一些Jackson注释来完成您需要的操作:
public abstract class UserDefinedResponse {
@JsonIgnore
public String customString1;
@JsonIgnore
public String customString2;
@JsonIgnore
public String customString3;
@JsonIgnore
public String customString4;
@JsonIgnore // Remove if clientId must be serialized
public String clientId;
private Map<String, Object> dynamicProperties = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> getDynamicProperties() {
Mapper.fillDynamicProperties(this, this.dynamicProperties);
return this.dynamicProperties;
}
@JsonAnySetter
public void setDynamicProperty(String name, Object value) {
this.dynamicProperties.put(name, value);
Mapper.setDynamicProperty(this.dynamicProperties, name, this);
}
}
对于产品实体和客户1:
public class ProductMapperClient1 extends Mapper<Product> {
@Override
protected void mapFromEntity(Product response, Map<String, Object> dynamicProperties) {
// Actual mapping from Product and CLIENT_1 to map
dynamicProperties.put("supplier", response.customString1);
dynamicProperties.put("warehouse", response.customString2);
}
@Override
protected void mapToEntity(Map<String, Object> dynamicProperties, String name, Product response) {
// Actual mapping from map and CLIENT_1 to Product
String property = (String) dynamicProperties.get(name);
if ("supplier".equals(name)) {
response.customString1 = property;
} else if ("warehouse".equals(name)) {
response.customString2 = property;
}
}
}
公共类ProductMapPerClient 1扩展了映射器{
@凌驾
受保护的void mapFromEntity(产品响应、映射动态属性){
//从产品和客户_1到映射的实际映射
dynamicProperties.put(“供应商”,response.customString1);
dynamicProperties.put(“仓库”,response.customString2);
}
@凌驾
受保护的void映射实体(映射动态属性、字符串名称、产品响应){
//从地图和客户_1到产品的实际映射
字符串属性=(字符串)dynamicProperties.get(名称);
如果(“供应商”。等于(名称)){
response.customString1=属性;
}否则,如果(“仓库”。等于(名称)){
response.customString2=属性;
}
}
}
其思想是每个(实体、客户机)对都有一个特定的映射器。如果您有许多实体和/或客户端,那么您可以考虑动态地填充映射器的映射,或者从一些配置文件中读取并使用反射来读取实体的属性。但是,当某些API响应在代码的不同部分被重用时,使用该类将强制并标准化响应。至于多个类,我看不出它们是如何链接到并发用户的。我会在运行时更改根据请求和客户机返回的字段。JVM将类加载到内存中,以便它们消耗堆空间-Classloader也是一个对象。我假设您的用例将基于“动态”生成的类。在最坏的情况下,它可能会导致内存泄漏和性能错误-以下是关于它的文章。感谢Federico的回答。我会试试看,今天再给你回复。工作很有魅力。解决方案在@JsonAnyGetter中
public class ProductMapperClient1 extends Mapper<Product> {
@Override
protected void mapFromEntity(Product response, Map<String, Object> dynamicProperties) {
// Actual mapping from Product and CLIENT_1 to map
dynamicProperties.put("supplier", response.customString1);
dynamicProperties.put("warehouse", response.customString2);
}
@Override
protected void mapToEntity(Map<String, Object> dynamicProperties, String name, Product response) {
// Actual mapping from map and CLIENT_1 to Product
String property = (String) dynamicProperties.get(name);
if ("supplier".equals(name)) {
response.customString1 = property;
} else if ("warehouse".equals(name)) {
response.customString2 = property;
}
}
}