Java 使用Jackson和json视图排除json中的字段

Java 使用Jackson和json视图排除json中的字段,java,json,jackson,json-view,Java,Json,Jackson,Json View,我正在根据需要创建一个动态json,这是一个很棒的库,我现在正在使用这个库一段时间。 最近,我的一个用例遇到了一个问题,让我把代码放在第一位 用户类 屏幕InfoPojo类 运行代码 预期结果 问题 在我的用例中,我有一个类Screen InfoPoJo,它与parentScreen引用同一个类, 我正在尝试获取父对象的特定字段(“parentScreen.id”)instate我正在获取在子对象/目标对象(“id”、“name”、“createdBy.name”、“lastUpdatedBy.

我正在根据需要创建一个动态json,这是一个很棒的库,我现在正在使用这个库一段时间。 最近,我的一个用例遇到了一个问题,让我把代码放在第一位

用户类 屏幕InfoPojo类 运行代码 预期结果 问题 在我的用例中,我有一个类Screen InfoPoJo,它与parentScreen引用同一个类, 我正在尝试获取父对象的特定字段(“parentScreen.id”)instate我正在获取在子对象/目标对象(“id”、“name”、“createdBy.name”、“lastUpdatedBy.mobileNo”、“parentScreen.id”)上定义的所有字段,并且父对象响应再次是递归的!我注意到只有在类有自己的引用的情况下才会发生这种情况,我将User类引用放置为两个不同的字段createdBylastedby,并尝试获取“name”“mobileNo”,分别工作正常

任何解决这个问题的建议都会非常有用


感谢

序列化对象最灵活的方法是编写自定义序列化程序

如果我正确理解了您的需求,以下序列化程序可能会工作:

public class CustomScreenInfoSerializer extends JsonSerializer<ScreenInfoPojo> {

    @Override
    public void serialize(ScreenInfoPojo value, JsonGenerator gen, SerializerProvider serializers)
            throws IOException, JsonProcessingException {
        gen.writeStartObject();
        gen.writeNumberField("id", value.getId());
        gen.writeStringField("name", value.getName());
        gen.writeFieldName("createdBy");
        gen.writeStartObject();
        gen.writeStringField("name", value.getCreatedBy().getName());
        gen.writeEndObject();
        gen.writeFieldName("lastUpdatedBy");
        gen.writeStartObject();
        gen.writeStringField("mobileNo", value.getLastUpdatedBy().getMobileNo());
        gen.writeEndObject();
        if (value.getParentScreen() == null) {
            gen.writeNullField("parentScreen");
        }
        else {
            gen.writeFieldName("parentScreen");
            gen.writeStartObject();
            gen.writeNumberField("id", value.getParentScreen().getId());
            gen.writeEndObject();
        }
        gen.writeEndObject();

    }

}
产生

[
   {
      "id": 1,
      "name": "Screen1",
      "createdBy": {
         "name": "ABC"
      },
      "lastUpdatedBy": {
         "mobileNo": "123456789"
      },
      "parentScreen": null
   },
   {
      "id": 2,
      "name": "Screen2",
      "createdBy": {
         "name": "ABC"
      },
      "lastUpdatedBy": {
         "mobileNo": "123456789"
      },
      "parentScreen": {
         "id": 1
      }
   },
   {
      "id": 3,
      "name": "Screen3",
      "createdBy": {
         "name": "ABC"
      },
      "lastUpdatedBy": {
         "mobileNo": "123456789"
      },
      "parentScreen": {
         "id": 2
      }
   },
   {
      "id": 4,
      "name": "Screen4",
      "createdBy": {
         "name": "ABC"
      },
      "lastUpdatedBy": {
         "mobileNo": "123456789"
      },
      "parentScreen": {
         "id": 3
      }
   }
]

对。Include子句不适用于对同一类的引用

你能做到吗

根据github指令从源代码编译

允许更新函数JsonViewSerializer.JsonWriter.field

查找:

和注释else子句

        if(match == null) {
            match = this.currentMatch;
        } else {
            //prefix = "";
        }
你会得到预期的结果。但是我不知道它将如何影响其他过滤器

若要获得更多控制权,可以向JsonView类添加属性

例如:

在JsonView中添加:

private boolean ignorePathIfClassRegistered = true;

     public boolean isIgnorePathIfClassRegistered() {
            return ignorePathIfClassRegistered;
        }

        public JsonView1<T>  setIgnorePathIfClassRegistered(boolean ignorePathIfClassRegistered) {
            this.ignorePathIfClassRegistered = ignorePathIfClassRegistered;
            return this;
        }
您可以在示例中使用它,如:

JsonView<List<ScreenInfoPojo>> viwevedObject = JsonView
        .with(screens)
        .onClass(ScreenInfoPojo.class,
                Match.match()
                        .exclude("*")
                        .include("id","name")
                        .include("createdBy.name")
                        .include("lastUpdatedBy.mobileNo")
                        .include("parentScreen.id"))
        .setIgnorePathIfClassRegistered(false);

ObjectMapper mapper = new ObjectMapper().registerModule(new JsonViewModule());
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);

String json = mapper.writeValueAsString(viwevedObject);
JsonView-viwevedObject=JsonView
.带(屏幕)
.onClass(屏幕InfoPoJo.class,
Match.Match()
.不包括(“*”)
.包括(“身份证”、“姓名”)
.include(“createdBy.name”)
.include(“lastdupdateby.mobileNo”)
.include(“parentScreen.id”))
.setIgnorePathIfClassRegistered(假);
ObjectMapper mapper=新的ObjectMapper().registerModule(新的JsonViewModule());
configure(SerializationFeature.INDENT_输出,true);
字符串json=mapper.writeValueAsString(viwevedObject);

您只需在json响应中不需要的字段上使用jackson annotation@jsonignore


我不知道您是否可以在代码上使用任何注释。如果是这样的话,这是没有用的

你能简单地用
id
属性创建另一个POJO并将其分配给
parentScreen
属性吗?不,我做不到为什么?从我的角度来看,它是一个独特的实体,有点像
ScreenRefPojo
。我的应用程序有多个类(pojo),并且在运行时应用了匹配,这意味着根据客户机的要求,它将使用属性(使用ajax),因此创建一个不同的类将增加额外的开销。我看到您在json视图中打开了一个问题(我同意您的代码应该按预期运行),但您是否至少尝试过排除
parentScreen.*
和/或
parentScreen.name,parentScreen.createdBy…
?感谢您的回答,如果我必须在一个或两个类中处理此问题,我可以应用此解决方案,但遗憾的是,我有许多类(实体)面对这个问题和这个json属性,我对同一api的不同请求进行了更改,因此我不能对实体类使用自定义序列化程序,我必须使其成为动态的。是的,使用这种方法,他只需添加一个带有父id的额外字段,以使代码重构的引用仍然最少。看起来非常简单。感谢您宝贵的回答,事实上我已经做了,我不想修改库源代码,但似乎没有其他方法可以接受这项工作。感谢您花费宝贵的时间。
public class CustomScreenInfoSerializer extends JsonSerializer<ScreenInfoPojo> {

    @Override
    public void serialize(ScreenInfoPojo value, JsonGenerator gen, SerializerProvider serializers)
            throws IOException, JsonProcessingException {
        gen.writeStartObject();
        gen.writeNumberField("id", value.getId());
        gen.writeStringField("name", value.getName());
        gen.writeFieldName("createdBy");
        gen.writeStartObject();
        gen.writeStringField("name", value.getCreatedBy().getName());
        gen.writeEndObject();
        gen.writeFieldName("lastUpdatedBy");
        gen.writeStartObject();
        gen.writeStringField("mobileNo", value.getLastUpdatedBy().getMobileNo());
        gen.writeEndObject();
        if (value.getParentScreen() == null) {
            gen.writeNullField("parentScreen");
        }
        else {
            gen.writeFieldName("parentScreen");
            gen.writeStartObject();
            gen.writeNumberField("id", value.getParentScreen().getId());
            gen.writeEndObject();
        }
        gen.writeEndObject();

    }

}
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(ScreenInfoPojo.class, new CustomScreenInfoSerializer());
mapper.registerModule(module);
String json = mapper.writeValueAsString(screens);
System.out.println(json);
[
   {
      "id": 1,
      "name": "Screen1",
      "createdBy": {
         "name": "ABC"
      },
      "lastUpdatedBy": {
         "mobileNo": "123456789"
      },
      "parentScreen": null
   },
   {
      "id": 2,
      "name": "Screen2",
      "createdBy": {
         "name": "ABC"
      },
      "lastUpdatedBy": {
         "mobileNo": "123456789"
      },
      "parentScreen": {
         "id": 1
      }
   },
   {
      "id": 3,
      "name": "Screen3",
      "createdBy": {
         "name": "ABC"
      },
      "lastUpdatedBy": {
         "mobileNo": "123456789"
      },
      "parentScreen": {
         "id": 2
      }
   },
   {
      "id": 4,
      "name": "Screen4",
      "createdBy": {
         "name": "ABC"
      },
      "lastUpdatedBy": {
         "mobileNo": "123456789"
      },
      "parentScreen": {
         "id": 3
      }
   }
]
        if(match == null) {
            match = this.currentMatch;
        } else {
            prefix = "";
        }
        if(match == null) {
            match = this.currentMatch;
        } else {
            //prefix = "";
        }
private boolean ignorePathIfClassRegistered = true;

     public boolean isIgnorePathIfClassRegistered() {
            return ignorePathIfClassRegistered;
        }

        public JsonView1<T>  setIgnorePathIfClassRegistered(boolean ignorePathIfClassRegistered) {
            this.ignorePathIfClassRegistered = ignorePathIfClassRegistered;
            return this;
        }
        if(match == null) {
            match = this.currentMatch;
        } else {
            if (result.isIgnorePathIfClassRegistered())
            prefix = "";
        }
JsonView<List<ScreenInfoPojo>> viwevedObject = JsonView
        .with(screens)
        .onClass(ScreenInfoPojo.class,
                Match.match()
                        .exclude("*")
                        .include("id","name")
                        .include("createdBy.name")
                        .include("lastUpdatedBy.mobileNo")
                        .include("parentScreen.id"))
        .setIgnorePathIfClassRegistered(false);

ObjectMapper mapper = new ObjectMapper().registerModule(new JsonViewModule());
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);

String json = mapper.writeValueAsString(viwevedObject);