Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何通过Jackson和MongoDB传递JSON消息中的属性?_Java_Json_Spring_Jackson_Microservices - Fatal编程技术网

Java 如何通过Jackson和MongoDB传递JSON消息中的属性?

Java 如何通过Jackson和MongoDB传递JSON消息中的属性?,java,json,spring,jackson,microservices,Java,Json,Spring,Jackson,Microservices,我们有一个微服务,它从队列中获取一些JSON数据,稍微处理一下,然后再通过队列发送进一步处理的结果。在微服务中,我们不直接使用JSONObjectan likes,而是使用Jackson将JSON映射到Java类 处理时,微服务只对传入消息的某些属性感兴趣,而不是所有属性。想象一下它刚刚收到 { "operand1": 3, "operand2": 5, /* other properties may come here */ } 并发送: { "operand

我们有一个微服务,它从队列中获取一些JSON数据,稍微处理一下,然后再通过队列发送进一步处理的结果。在微服务中,我们不直接使用
JSONObject
an likes,而是使用Jackson将JSON映射到Java类

处理时,微服务只对传入消息的某些属性感兴趣,而不是所有属性。想象一下它刚刚收到

{
    "operand1": 3,
    "operand2": 5,
    /* other properties may come here */
}
并发送:

{
    "operand1": 3,
    "operand2": 5,
    "multiplicationResult": 15,
    /* other properties may come here */
}
如果不在类中显式映射消息的其他属性,我如何挖掘或传递对此服务不感兴趣的消息的其他属性?

就本微服务而言,拥有如下结构就足够了:

public class Task {
   public double operand1;
   public double operand2;
   public double multiplicationResult;
}
但是,如果我不映射所有其他属性,它们将丢失


如果我真的映射了它们,那么每次消息结构发生变化时,我都必须更新这个微服务的模型,这需要付出努力,而且容易出错。

这两个都不是很好,但是你可以做的是,将结构分为两部分-一个由微服务反序列化的结构化部分,还有一个单独的“additionalFields”字段,其中包含您的其他JSON,然后您可以在该字段中修改JSON,而无需更改
Task
。您可以将嵌套的JSON添加为
字符串

public class Task {
   public double operand1;
   public double operand2;
   public double multiplicationResult;
   public String additionalFields
}
或者,您可以添加一个
映射
,这将允许您添加键值对,但同样,您将失去类型安全性:

public class Task {
   public double operand1;
   public double operand2;
   public double multiplicationResult;
   public Map<String, Object> additionalFields
}
公共类任务{
公共双操作数1;
公开双代号2;
公共双重乘法结果;
公共地图附加字段
}

在敏捷结构的情况下,最简单的方法是使用Map而不是自定义POJO:

很容易从JSON中读取,例如使用
JsonParser解析器
(java文档):

您甚至可以通过将
Map
包装为
Task
来实现它,如下所示:

public class Task {
    private final Map<String, Object> fields;

    public final double operand1;
    // And so on...

    @JsonCreator
    public Task(Map<String, Object> fields) {
        this.fields = fields;

        this.operand1 = 0; /* Extract desired values from the Map */
    }

    @JsonValue
    public Map<String, Object> toMap() {
        return this.fields;
    }
}
public class Task {
    @JsonView({ServiceView.class})
    public double operand1;
    @JsonView({ServiceView.class})
    public double operand2;
    @JsonView({ServiceView.class})
    public double multiplicationResult;

    public Object otherField;

   public interface ServiceView{}
}
    myService.send(new ObjectMapper().writerWithView(ServiceView.class)
                                     .writeValueAsString(task));

将@JsonView添加到POJO中,如下所示:

public class Task {
    private final Map<String, Object> fields;

    public final double operand1;
    // And so on...

    @JsonCreator
    public Task(Map<String, Object> fields) {
        this.fields = fields;

        this.operand1 = 0; /* Extract desired values from the Map */
    }

    @JsonValue
    public Map<String, Object> toMap() {
        return this.fields;
    }
}
public class Task {
    @JsonView({ServiceView.class})
    public double operand1;
    @JsonView({ServiceView.class})
    public double operand2;
    @JsonView({ServiceView.class})
    public double multiplicationResult;

    public Object otherField;

   public interface ServiceView{}
}
    myService.send(new ObjectMapper().writerWithView(ServiceView.class)
                                     .writeValueAsString(task));
然后使用
com.fasterxml.jackson.databind.ObjectMapper
将其发送到您的服务,如下所示:

public class Task {
    private final Map<String, Object> fields;

    public final double operand1;
    // And so on...

    @JsonCreator
    public Task(Map<String, Object> fields) {
        this.fields = fields;

        this.operand1 = 0; /* Extract desired values from the Map */
    }

    @JsonValue
    public Map<String, Object> toMap() {
        return this.fields;
    }
}
public class Task {
    @JsonView({ServiceView.class})
    public double operand1;
    @JsonView({ServiceView.class})
    public double operand2;
    @JsonView({ServiceView.class})
    public double multiplicationResult;

    public Object otherField;

   public interface ServiceView{}
}
    myService.send(new ObjectMapper().writerWithView(ServiceView.class)
                                     .writeValueAsString(task));

在Spring/Javaconfig中配置ObjectMapperbean,并将属性设置为忽略缺少的属性。在需要的地方注入相同的bean

@Bean
public ObjectMapper objectMapper() {
    return new ObjectMapper()
       .configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

还有一种可能性:使用
@JsonAnySetter
和/或
@JsonAnyGetter
创建嵌入的“动态”属性。这里有一个例子:


但其基本思想是,可以通过
@JsonAnySetter
注释方法(或新版本中的字段)从JSON绑定“任何其他内容”;以及通过类似的
@JsonAnyGetter
方法/字段(具有
Map
值)获取序列化的“额外属性”。

如前所述,
@JsonAnyGetter
@JsonAnySetter
可能是您的最佳选择。 我认为你可以尽可能灵活地做,尽可能多的类型安全

我想到的第一件事就是准确地将你需要的属性和其他属性分开

核心 Calculation.java 一个简单的不可变的“计算”对象。 当然,它可以用任何其他方式设计,但我相信,不变性使它更简单、更可靠

最终类计算{
私人决赛双a;
私人决赛双b;
私人最终运营;
私人最终双重结果;
私人计算(最终双a、最终双b、最终操作操作、最终双结果){
这个a=a;
这个.b=b;
这个操作=操作;
this.result=结果;
}
静态计算(最终双a、最终双b、最终运行操作、最终双结果){
返回新计算(a、b、操作、结果);
}
计算{
返回新计算(a,b,operation,operation.applyAsDouble(a,b));
}
双getA(){
返回a;
}
双getB(){
返回b;
}
操作getOperation(){
返回操作;
}
Double-getResult(){
返回结果;
}
}
Operation.java 在枚举中定义的一个简单的计算策略,因为Jackson处理枚举非常好

enum操作
实现DoubleBinaryOperator{
加{
@凌驾
公共双精度应用双精度(最终双精度a,最终双精度b){
返回a+b;
}
},
减去{
@凌驾
公共双精度应用双精度(最终双精度a,最终双精度b){
返回a-b;
}
},
倍增{
@凌驾
公共双精度应用双精度(最终双精度a,最终双精度b){
返回a*b;
}
},
分开{
@凌驾
公共双精度应用双精度(最终双精度a,最终双精度b){
返回a/b;
}
}
}
杰克逊映射 AbstractTask.java 请注意,此类旨在提供一个值,但将其余的值收集到卫星地图中,该地图由
@JsonAnySetter
@JsonAnyGetter
注释的方法管理。 映射和方法可以安全地声明为私有,因为Jackson并不真正关心保护级别(这很好)。 此外,它是以不变的方式设计的,除了底层映射可以被浅层复制到新值之外

抽象类抽象任务
实施供应商{
@杰索尼奥雷
private final Map rest=new LinkedHashMap();
受保护的抽象任务总任务数(V值);
最终T与(最终V值){
最终抽象任务dto=toTask(值);
dto.rest.putAll(rest);
@抑制警告(“未选中”)
最终T castDto=(T)dto;
返回castDto;
}
@JSONANYSETER
@抑制警告(“未使用”)
私有无效集(最终字符串名称、最终对象值){
rest.put(名称、值);
}
@JsonAnyGetter
@抑制警告
(mongodb-shell)
> use test
(bash)
$ curl -v -X GET http://localhost:9000/foo
(mongodb-shell)
> db.calculations.find()
(bash)
$ curl -v -X PUT -H 'Content-Type: application/json' \
    --data '{"a":3,"b":4,"operation":"MULTIPLY","result":12,"foo":"FOO","bar":"BAR"}' \
    http://localhost:9000/foo
(mongodb-shell)
> db.calculations.find()
(bash)
$ curl -v -X GET http://localhost:9000/foo
(bash)
curl -v -X DELETE http://localhost:9000/foo
(mongodb-shell)
> db.calculations.find()
// Reading data
String jsonString restTemplate.getForObject(request, String.class);
MyClass actualObj = new ObjectMapper().readValue(jsonString, MyClass.class);
actualObj.setOriginalJson(jsonString);

// Writing data
String jsonString = actualObj.getOriginalJson();
restTemplate.postForLocation(URI.create(url), jsonString);

@JsonIgnoreProperties(ignoreUnknown = true)
public class MyClass {
    private String property1;
    private String property2;

    @JsonIgnore
    private String originalJson;

    public String getOriginalJson() {
        return originalJson;
    }

    public void setOriginalJson(String originalJson) {
        this.originalJson = originalJson;
    }
}