英文:
How can I use @JsonView / @JsonBackReference / @JsonIdentityInfo to serialize desired child elements depending on scenario
问题
考虑使用如下的DTO结构:
@Data
class Profile {
@JsonView({Profile.Views.Simple.class, Views.AllFields.class})
String name;
@JsonView(Profile.Views.AllFields.class)
Collection<Image> images;
static class Views {
static class Simple {
}
static class AllFields {
}
}
}
@Data
@AllArgsConstructor
class Image {
@JsonView({Image.Views.Simple.class, Profile.Views.AllFields.class})
String name;
@JsonView(Image.Views.AllFields.class)
Profile profile;
static class Views {
static class Simple {
}
static class AllFields {
}
}
}
我可以想象一个相当简单的场景,根据操作的根源,我想要具有根实体的JSON输出,以及相关对象的第一级,例如:
获取用户:
{
"name": "userName",
"images": [
{
"name": "image1Name"
}
]
}
或者获取图像时:
{
"name": "imageName",
"user": {
"name": "userName"
}
}
是否可以使用类似 @JsonView
的技巧,还是我必须为不同的情况创建单独的DTO?
Jackson的ObjectMapper似乎只能处理单个类的视图,因此类似以下的尝试:
Profile p = new Profile();
p.setName("ProfileName");
p.setImages(Arrays.asList(new Image("ImageName1", p), new Image("ImageName", p)));
System.out.println(mapper
.writerWithView(Profile.Views.AllFields.class)
.withView(Image.Views.Simple.class)
.writeValueAsString(p));
System.out.println(mapper
.writerWithView(Profile.Views.Simple.class)
.withView(Image.Views.Simple.class)
.writeValueAsString(p.getImages().iterator().next()));
结果为空的JSON。
英文:
Consider having DTOs like this
@Data
class Profile {
@JsonView({Profile.Views.Simple.class, Views.AllFields.class})
String name;
@JsonView(Profile.Views.AllFields.class)
Collection<Image> images;
static class Views {
static class Simple {
}
static class AllFields {
}
}
}
@Data
@AllArgsConstructor
class Image {
@JsonView({Image.Views.Simple.class,Profile.Views.AllFields.class})
String name;
@JsonView(Image.Views.AllFields.class)
Profile profile;
static class Views {
static class Simple {
}
static class AllFields {
}
}
}
I can imagine quite simple scenario, that depending on what is the root of the operation, I would like to have JSON output of root entities with the first level of related objects eg.
fetching Users
{
name: userName,
images: [
{
name: image1Name
}
]
}
or when fetching images
{
name: imageName,
user: {
name: userName
}
}
Is is possible to use some sort of @JsonView trick, or do I have to create seprate DTOs for different scenarios?
Jackson ObjectMapper seems to be able to handle only single class view, thus attempt like
Profile p = new Profile();
p.setName("ProfileName");
p.setImages(Arrays.asList(new Image("ImageName1", p), new Image("ImageName", p)))
System.out.println(mapper
.writerWithView(Profile.Views.AllFields.class)
.withView(Image.Views.Simple.class)
.writeValueAsString(p));
System.out.println(mapper
.writerWithView(Profile.Views.Simple.class)
.withView(Image.Views.Simple.class)
.writeValueAsString(p.getImages().iterator().next()));
results in empty jsons.
答案1
得分: 1
{
"name": "ProfileName1",
"images": [
{
"name": "ImageName1"
},
{
"name": "ImageName2"
}
]
}
{
"name": "ImageName1",
"profile": {
"name": "ProfileName1"
}
}
英文:
Jackson is kind of magic (when it works the way you want).
First problem is to solve the infinite recursion due to cyclic dependency using @JsonIdentityInfo
.
Second problem is to hide specific fields while serializing respective beans using @JsonView
.
Profile.java
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "name")
class Profile {
String name;
@JsonView(Views.Profile.class)
Collection<Image> images;
// setter getter or lombok annotations
}
Image.java
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "name")
class Image {
String name;
@JsonView(Views.Image.class)
Profile profile;
// constructor, setter getter or lombok annotations
}
Views.java
class Views {
public static class Profile {}
public static class Image {}
}
And Finally Main.java
public static void main(String[] args) throws IOException {
Profile p1 = new Profile();
p1.setName("ProfileName1");
Profile p2 = new Profile();
p2.setName("ProfileName2");
Image image1 = new Image("ImageName1", p1);
Image image2 = new Image("ImageName2", p2);
p1.setImages(Arrays.asList(image1, image2));
String json = mapper
.writerWithView(Views.Profile.class)
.writeValueAsString(p1);
System.out.println(json);
json = mapper.
writerWithView(Views.Image.class)
.writeValueAsString(image1);
System.out.println(json);
}
Output:
// p1
{
"name": "ProfileName1",
"images": [
{
"name": "ImageName1"
},
{
"name": "ImageName2"
}
]
}
// image1
{
"name": "ImageName1",
"profile": {
"name": "ProfileName1"
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论