gpt4 book ai didi

java - jackson 序列化/反序列化 : Dynamic properties and fields

转载 作者:行者123 更新时间:2023-11-30 08:10:48 26 4
gpt4 key购买 nike

我使用 Spring MVC 来驱动我当前使用的应用程序的 API。 API 响应的序列化是通过 Jackson 的 ObjectMapper 完成的。我面临以下情况,我们正在扩展我们的一些对象以支持 UserDefinedFields (UDF),这在下面的抽象 UserDefinedResponse 中显示。作为一个 SaaS 解决方案,多个客户端有不同的配置,这些配置存储在数据库中用于他们的自定义字段。

这个问题的目标是能够用他们的 UDF 数据响应每个客户端。这需要

  1. 将字段 customString1customString2 动态重命名为它们相应的 UDF 标签
  2. 删除未定义的 UDF 字段(示例客户端仅使用 4 个字段中的 2 个。

抽象响应示例

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 = "仓库"

为此客户序列化 Product 应该会产生类似于以下内容的结果:

{
"id" : 1234,
"name" : "MacBook Air",
"price" : 1299,
"supplier" : "Apple",
"warehouse" : "New York warehouse"
}

最佳答案

我认为您可以借助一些 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);
}
}

首先,使用 @JsonIgnore 注释基类的所有属性,因为这些不会成为响应的一部分。然后,使用 @JsonAnyGetter 注释来展平 dynamicProperties 映射,它将保存动态属性。最后,@JsonAnySetter 注释旨在供 Jackson 在反序列化时使用。

缺少的部分是Mapper实用类:

public abstract class Mapper<T extends UserDefinedResponse> {

private static final Map<Class<T>, Map<String, Mapper<T>>> MAPPERS = new HashMap<>();

static {
// Mappers for Products
Map<String, Mapper<Product>> productMappers = new HashMap<>();
productMappers.put("CLIENT_1", new ProductMapperClient1());
productMappers.put("CLIENT_2", new ProductMapperClient2());
// etc for rest of clients
MAPPERS.put(Product.class, productMappers);

// Mappers for Providers
Map<String, Mapper<Provider>> providerMappers = new HashMap<>();
providerMappers.put("CLIENT_1", new ProviderMapperClient1());
providerMappers.put("CLIENT_2", new ProviderMapperClient2());
// etc for rest of clients
MAPPERS.put(Provider.class, providerMappers);

// etc for rest of entities
// (each entity needs to add specific mappers for every client)
}

protected Mapper() {
}

public static void fillDynamicProperties(T response, Map<String, Object> dynamicProperties) {
// Get mapper for entity and client
Mapper<T> mapper = MAPPERS.get(response.getClass()).get(response.clientId);
// Perform entity -> map mapping
mapper.mapFromEntity(response, dynamicProperties);
}

public static void setDynamicProperty(Map<String, Object> dynamicProperties, String name, T response) {
// Get mapper for entity and client
Mapper<T> mapper = MAPPERS.get(response.getClass()).get(response.clientId);
// Perform map -> entity mapping
mapper.mapToEntity(dynamicProperties, name, response);
}

protected abstract void mapFromEntity(T response, Map<String, Object> dynamicProperties);

protected abstract void mapToEntity(Map<String, Object> dynamicProperties, String name, T response);
}

对于产品实体和客户 CLIENT_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;
}
}
}

想法是每个(实体、客户端)对都有一个特定的映射器。如果您有许多实体和/或客户端,那么您可能会考虑动态填充映射器的映射,可能会从一些配置文件中读取并使用反射来读取实体的属性。

关于java - jackson 序列化/反序列化 : Dynamic properties and fields,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31505407/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com