使用 Jackson 和 Json-View 排除 json 中的字段
Posted
技术标签:
【中文标题】使用 Jackson 和 Json-View 排除 json 中的字段【英文标题】:Exclude fields in json Using Jackson and Json-View 【发布时间】:2017-10-18 05:55:27 【问题描述】:我正在使用json-view 根据我的需要创建一个动态 json,这是一个很棒的库,我现在使用这个库有一段时间了。 最近我的一个用例遇到问题,让我先放我的代码
用户类
public class User
private String name;
private String emailId;
private String mobileNo;
public String getName()
return name;
public void setName(String name)
this.name = name;
public String getEmailId()
return emailId;
public void setEmailId(String emailId)
this.emailId = emailId;
public String getMobileNo()
return mobileNo;
public void setMobileNo(String mobileNo)
this.mobileNo = mobileNo;
ScreenInfoPojo 类
public class ScreenInfoPojo
private Long id;
private String name;
private ScreenInfoPojo parentScreen;
private User createdBy;
private User lastUpdatedBy;
public Long getId()
return id;
public void setId(Long id)
this.id = id;
public String getName()
return name;
public void setName(String name)
this.name = name;
public ScreenInfoPojo getParentScreen()
return parentScreen;
public void setParentScreen(ScreenInfoPojo parentScreen)
this.parentScreen = parentScreen;
public User getCreatedBy()
return createdBy;
public void setCreatedBy(User createdBy)
this.createdBy = createdBy;
public User getLastUpdatedBy()
return lastUpdatedBy;
public void setLastUpdatedBy(User lastUpdatedBy)
this.lastUpdatedBy = lastUpdatedBy;
运行代码
public class TestMain
public static void main(String[] args) throws JsonProcessingException
User user=new User();
user.setName("ABC");
user.setEmailId("dev@abc123.com");
user.setMobileNo("123456789");
ScreenInfoPojo screen1=new ScreenInfoPojo();
screen1.setId(1l);
screen1.setName("Screen1");
screen1.setCreatedBy(user);
screen1.setLastUpdatedBy(user);
ScreenInfoPojo screen2=new ScreenInfoPojo();
screen2.setId(2l);
screen2.setName("Screen2");
screen2.setParentScreen(Screen1);
screen2.setCreatedBy(user);
screen2.setLastUpdatedBy(user);
ScreenInfoPojo screen3=new ScreenInfoPojo();
screen3.setId(3l);
screen3.setName("Screen3");
screen3.setParentScreen(Screen2);
screen3.setCreatedBy(user);
screen3.setLastUpdatedBy(user);
ScreenInfoPojo screen4=new ScreenInfoPojo();
screen4.setId(4l);
screen4.setName("Screen4");
screen4.setParentScreen(Screen3);
screen4.setCreatedBy(user);
screen4.setLastUpdatedBy(user);
List<ScreenInfoPojo> screens=new ArrayList<>();
screens.add(screen1);
screens.add(screen2);
screens.add(screen3);
screens.add(screen4);
ObjectMapper mapper = new ObjectMapper().registerModule(new JsonViewModule());
String json = mapper.writeValueAsString(JsonView.with(screens).onClass(ScreenInfoPojo.class, Match.match()
.exclude("*")
.include("id","name","createdBy.name","lastUpdatedBy.mobileNo","parentScreen.id")));
System.out.println("json"+json);
结果
[
"id": 1,
"name": "Screen1",
"parentScreen": null,
"createdBy":
"name": "ABC"
,
"lastUpdatedBy":
"mobileNo": "123456789"
,
"id": 2,
"name": "Screen2",
"parentScreen":
"id": 1,
"name": "Screen1",
"parentScreen": null,
"createdBy": ,
"lastUpdatedBy":
,
"createdBy":
"name": "ABC"
,
"lastUpdatedBy":
"mobileNo": "123456789"
,
"id": 3,
"name": "Screen3",
"parentScreen":
"id": 2,
"name": "Screen2",
"parentScreen":
"id": 1,
"name": "Screen1",
"parentScreen": null,
"createdBy": ,
"lastUpdatedBy":
,
"createdBy": ,
"lastUpdatedBy":
,
"createdBy":
"name": "ABC"
,
"lastUpdatedBy":
"mobileNo": "123456789"
,
"id": 4,
"name": "Screen4",
"parentScreen":
"id": 3,
"name": "Screen3",
"parentScreen":
"id": 2,
"name": "Screen2",
"parentScreen":
"id": 1,
"name": "Screen1",
"parentScreen": null,
"createdBy": ,
"lastUpdatedBy":
,
"createdBy": ,
"lastUpdatedBy":
,
"createdBy": ,
"lastUpdatedBy":
,
"createdBy":
"name": "ABC"
,
"lastUpdatedBy":
"mobileNo": "123456789"
]
预期结果
[
"id": 1,
"name": "Screen1",
"parentScreen": null,
"createdBy":
"name": "ABC"
,
"lastUpdatedBy":
"mobileNo": "123456789"
,
"id": 2,
"name": "Screen2",
"parentScreen":
"id": 1
,
"createdBy":
"name": "ABC"
,
"lastUpdatedBy":
"mobileNo": "123456789"
,
"id": 3,
"name": "Screen3",
"parentScreen":
"id": 2
,
"createdBy":
"name": "ABC"
,
"lastUpdatedBy":
"mobileNo": "123456789"
,
"id": 4,
"name": "Screen4",
"parentScreen":
"id": 3
,
"createdBy":
"name": "ABC"
,
"lastUpdatedBy":
"mobileNo": "123456789"
]
问题
在我的用例中,我有一个类 ScreenInfoPojo 与 parentScreen 引用相同的类, 我正在尝试获取父 ("parentScreen.id") 的特定字段/字段,因为我正在获取我在子/目标对象 ("id","name ","createdBy.name","lastUpdatedBy.mobileNo","parentScreen.id") 和父响应再次递归!我观察到的一件事只有在类有自己的引用的情况下才会发生,我将 User 类引用作为两个不同的字段 createdBy 和 lastUpdatedBy 并尝试分别获取 "name" 和 "mobileNo" 效果很好。
任何解决这个问题的建议都会非常有帮助!!!!
谢谢
【问题讨论】:
你能简单地用id
属性创建另一个POJO并将它分配给parentScreen
属性吗?
不,我做不到
为什么?从我的角度来看,它是一个独特的实体——类似于ScreenRefPojo
。
我的应用程序有多个类(pojo),并且在运行时应用了匹配,这意味着根据客户端的要求它将与属性(使用 ajax)一样,因此创建不同的类会增加额外的开销.
我看到您在 json-view 上打开了一个问题(我同意您的代码应该按预期运行),但您至少尝试排除 parentScreen.*
和/或 @987654331 @ ?
【参考方案1】:
是的。 Include 子句对同一个类的引用不起作用。
你能做到吗?
根据github指令从源码编译build from source
更新函数JsonViewSerializer.JsonWriter.fieldAllowed
找到:
if(match == null)
match = this.currentMatch;
else
prefix = "";
并注释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;
在 JsonViewSerializer.JsonWriter.fieldAllowed 函数中将 if 子句重写为:
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);
【讨论】:
感谢您的宝贵回答,实际上我已经这样做了,我不想修改库源代码,但似乎没有其他方法可以接受这项工作。感谢您花费宝贵的时间。【参考方案2】:您可以在 json 响应中不需要的字段上简单地使用 jackson 注释 @jsonignore。
我不知道您是否可以在代码上使用任何注释。如果是这样,这没用..
【讨论】:
是的,使用这种方法,他只需添加一个带有父 id 的附加字段,以仍然具有最少代码重构量的参考。看起来很简单。【参考方案3】:序列化对象最灵活的方法是编写自定义序列化器。
如果我正确理解了您的要求,以下序列化程序可能会起作用:
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
]
【讨论】:
感谢您的回答,如果我只能在一两个类中处理这个问题,我可以应用这个解决方案,但遗憾的是我有很多类(实体)面临这个问题,这个 json 属性是我的改变对于同一个 api 的不同请求,所以我不能对实体类使用自定义序列化程序,我必须使其成为动态的。以上是关于使用 Jackson 和 Json-View 排除 json 中的字段的主要内容,如果未能解决你的问题,请参考以下文章
com.fasterxml.jackson.databind.JsonSerializer 按键排除字段
JPA / Jackson - 反序列化时排除字段并在序列化时包含它们