下面是详解Struts2中json 相互引用死循环解决办法的完整攻略。
简介
在 Struts2 中,使用 JSON 返回数据时,如果包含相互引用的对象,就会出现死循环的情况。这是因为在序列化时,对象互相引用,导致 Gson 序列化器无法判断对象的终止条件从而产生栈溢出。解决这个问题的方法是给予 JSON 序列化器一些帮助,在序列化时忽略相互引用的部分。
解决方案
1. 使用 Jackson 序列化器
Jackson 是一个高性能的 JSON 序列化库,它支持完全的 JSON 规范并且可以与大量的 Java 框架集成。在 Struts2 的配置文件中,将默认的 JSON 序列化器 Gson 改为 Jackson 即可解决相互引用的问题。
<constant name="struts.mapper.class" value="org.apache.struts2.dispatcher.mapper.JacksonJaxbJsonMapper"/>
2. 添加 Jackson 库对相互引用的支持
在上一步中,将默认的 JSON 序列化器改为了 Jackson,但是默认情况下 Jackson 也无法处理相互引用的问题。需要添加 Jackson 库对相互引用的支持。
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class User {
private Long id;
private String name;
private Group group;
// getters and setters
}
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Group {
private Long id;
private String name;
private List<User> users;
// getters and setters
}
在类上添加 @JsonIdentityInfo 注解,其中 generator 属性指定了序列化时采用的引用生成器,property 属性指定了生成的引用标识属性。这样,在序列化时,只要检测到两个对象 id 相同,就会进行引用替换,从而避免了相互引用的死循环问题。
示例
例1:Gson 序列化器
public class User {
private Long id;
private String name;
private Group group;
// getters and setters
}
public class Group {
private Long id;
private String name;
private List<User> users;
// getters and setters
}
public class JsonAction extends ActionSupport {
private List<Group> groups;
// getters and setters
public String execute() throws Exception {
groups = new ArrayList<Group>();
Group group1 = new Group();
group1.setId(1L);
group1.setName("Group 1");
Group group2 = new Group();
group2.setId(2L);
group2.setName("Group 2");
groups.add(group1);
groups.add(group2);
User user1 = new User();
user1.setId(1L);
user1.setName("User 1");
user1.setGroup(group1);
User user2 = new User();
user2.setId(2L);
user2.setName("User 2");
user2.setGroup(group2);
User user3 = new User();
user3.setId(3L);
user3.setName("User 3");
user3.setGroup(group1);
group1.setUsers(Arrays.asList(user1, user3));
group2.setUsers(Arrays.asList(user2));
return SUCCESS;
}
public String toJson() {
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("application/json;charset=utf-8");
Gson gson = new Gson();
String json = gson.toJson(groups);
try {
response.getWriter().write(json);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
上述示例中使用了 Gson 序列化器,在执行 toJson 方法时返回字串完全错误。出现死循环的原因是 Group 中包含了多个 User 对象,User 中包含了一个 Group,导致序列化时出现了循环引用。
例2:Jackson 序列化器
<constant name="struts.mapper.class" value="org.apache.struts2.dispatcher.mapper.JacksonJaxbJsonMapper"/>
public class User {
private Long id;
private String name;
@JsonIgnoreProperties("users")
private Group group;
// getters and setters
}
public class Group {
private Long id;
private String name;
@JsonManagedReference
private List<User> users;
// getters and setters
}
public class JsonAction extends ActionSupport {
private List<Group> groups;
// getters and setters
public String execute() throws Exception {
groups = new ArrayList<Group>();
Group group1 = new Group();
group1.setId(1L);
group1.setName("Group 1");
Group group2 = new Group();
group2.setId(2L);
group2.setName("Group 2");
groups.add(group1);
groups.add(group2);
User user1 = new User();
user1.setId(1L);
user1.setName("User 1");
user1.setGroup(group1);
User user2 = new User();
user2.setId(2L);
user2.setName("User 2");
user2.setGroup(group2);
User user3 = new User();
user3.setId(3L);
user3.setName("User 3");
user3.setGroup(group1);
group1.setUsers(Arrays.asList(user1, user3));
group2.setUsers(Arrays.asList(user2));
return SUCCESS;
}
public String toJson() {
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("application/json;charset=utf-8");
ObjectMapper mapper = new ObjectMapper();
String json = null;
try {
json = mapper.writeValueAsString(groups);
} catch (JsonProcessingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
response.getWriter().write(json);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
上述示例中使用了 Jackson 序列化器,在执行 toJson 方法时正确地序列化了数据,避免了死循环的问题。在 User 类中,使用了 @JsonIgnoreProperties 注解,排除了序列化 users 属性,从而避免了嵌套序列化的问题。在 Group 类中,使用了 @JsonManagedReference 注解,指定了 users 属性为父对象,在反序列化时会自动添加到父对象中。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Struts2中json 相互引用死循环解决办法 - Python技术站