JSONObject().put 使用 List 递归地抛出 DefinedObjectException

JSONObject().put using a List Throws recursivelyDefinedObjectException

我有一个查询生成 List of Tickets 像这样使用休眠 :

Query query = session.createQuery(
        "SELECT T.id, T.Objet, T.Details, T.Etat,T.Severity, T.createDateTime, T.user, T.Attachment, U.lastName, L.nomLogiciel, V.nomVersion,T.AssignedTo,T.ClosedBy,T.closedDateTime,T.assignedDateTime, U.firstName, U.username, U.Email, U.Phone  FROM Ticket T, User U, Logiciel L, Version V "
        + "WHERE T.user= :user and T.user=U.user_id AND L.logiciel_id=T.Logiciel AND T.Version=V.version_id AND T.Etat!='fermer' ORDER BY T.createDateTime ")
        .setParameter("user", user);

我试图 put JSONObject 中的列表:

    List allTickets = ticketDao.getTicketsByUserDao(user);
    JSONObject jo = new JSONObject();
    jo.put("ticket", allTickets);

它抛出这个异常:

Hibernate: select ticket0_.ticket_id as col_0_0_, ticket0_.objet as col_1_0_, ticket0_.details as col_2_0_, ticket0_.etat as col_3_0_, ticket0_.severity as col_4_0_, ticket0_.createDateTime as col_5_0_, ticket0_.user_id as col_6_0_, ticket0_.attachment_path as col_7_0_, user1_.last_name as col_8_0_, logiciel2_.nom_logiciel as col_9_0_, version3_.nom_version as col_10_0_, ticket0_.assigned_to as col_11_0_, ticket0_.closed_by as col_12_0_, ticket0_.closedDateTime as col_13_0_, ticket0_.assignedDateTime as col_14_0_, user1_.first_name as col_15_0_, user1_.username as col_16_0_, user1_.email as col_17_0_, user1_.phone as col_18_0_, user4_.user_id as user_id1_9_, user4_.email as email2_9_, user4_.etat as etat3_9_, user4_.phone as phone4_9_, user4_.currentAccessDate as currenta5_9_, user4_.dateExpiration as dateexpi6_9_, user4_.first_name as first_na7_9_, user4_.lastAccessDate as lastacce8_9_, user4_.last_name as last_nam9_9_, user4_.password as passwor10_9_, user4_.structure_id as structu12_9_, user4_.username as usernam11_9_ from tickets ticket0_ cross join users user1_ cross join logiciel logiciel2_ cross join version version3_ inner join users user4_ on ticket0_.user_id=user4_.user_id where ticket0_.user_id=? and ticket0_.user_id=user1_.user_id and logiciel2_.logiciel_id=ticket0_.logiciel_id and ticket0_.version_id=version3_.version_id and ticket0_.etat<>'fermer' order by ticket0_.createDateTime
Hibernate: select tickets0_.user_id as user_id14_8_2_, tickets0_.ticket_id as ticket_i1_8_2_, tickets0_.ticket_id as ticket_i1_8_1_, tickets0_.assigned_to as assigned2_8_1_, tickets0_.attachment_path as attachme3_8_1_, tickets0_.closed_by as closed_b4_8_1_, tickets0_.details as details5_8_1_, tickets0_.etat as etat6_8_1_, tickets0_.logiciel_id as logiciel7_8_1_, tickets0_.objet as objet8_8_1_, tickets0_.severity as severity9_8_1_, tickets0_.version_id as version10_8_1_, tickets0_.assignedDateTime as assigne11_8_1_, tickets0_.closedDateTime as closedd12_8_1_, tickets0_.createDateTime as created13_8_1_, tickets0_.user_id as user_id14_8_1_, planificat1_.planif_id as planif_i1_4_0_, planificat1_.observation as observat2_4_0_, planificat1_.date_debut_planif as date_deb3_4_0_, planificat1_.date_debut_realise as date_deb4_4_0_, planificat1_.date_fin_planif as date_fin5_4_0_, planificat1_.date_fin_realise as date_fin6_4_0_, planificat1_.ticket_id as ticket_i7_4_0_ from tickets tickets0_ left outer join planification planificat1_ on tickets0_.ticket_id=planificat1_.ticket_id where tickets0_.user_id in (select user4_.user_id from tickets ticket0_ cross join users user1_ cross join logiciel logiciel2_ cross join version version3_ inner join users user4_ on ticket0_.user_id=user4_.user_id where ticket0_.user_id=? and ticket0_.user_id=user1_.user_id and logiciel2_.logiciel_id=ticket0_.logiciel_id and ticket0_.version_id=version3_.version_id and ticket0_.etat<>'fermer' )
Hibernate: select response0_.ticket_id as ticket_i4_5_0_, response0_.response_id as response1_5_0_, response0_.response_id as response1_5_1_, response0_.response as response2_5_1_, response0_.createDateTime as createda3_5_1_, response0_.ticket_id as ticket_i4_5_1_, response0_.user_id as user_id5_5_1_, user1_.user_id as user_id1_9_2_, user1_.email as email2_9_2_, user1_.etat as etat3_9_2_, user1_.phone as phone4_9_2_, user1_.currentAccessDate as currenta5_9_2_, user1_.dateExpiration as dateexpi6_9_2_, user1_.first_name as first_na7_9_2_, user1_.lastAccessDate as lastacce8_9_2_, user1_.last_name as last_nam9_9_2_, user1_.password as passwor10_9_2_, user1_.structure_id as structu12_9_2_, user1_.username as usernam11_9_2_, structure2_.structure_id as structur1_6_3_, structure2_.nom_structure as nom_stru2_6_3_ from responses response0_ inner join users user1_ on response0_.user_id=user1_.user_id left outer join structure structure2_ on user1_.structure_id=structure2_.structure_id where response0_.ticket_id=?
Hibernate: select response0_.ticket_id as ticket_i4_5_0_, response0_.response_id as response1_5_0_, response0_.response_id as response1_5_1_, response0_.response as response2_5_1_, response0_.createDateTime as createda3_5_1_, response0_.ticket_id as ticket_i4_5_1_, response0_.user_id as user_id5_5_1_, user1_.user_id as user_id1_9_2_, user1_.email as email2_9_2_, user1_.etat as etat3_9_2_, user1_.phone as phone4_9_2_, user1_.currentAccessDate as currenta5_9_2_, user1_.dateExpiration as dateexpi6_9_2_, user1_.first_name as first_na7_9_2_, user1_.lastAccessDate as lastacce8_9_2_, user1_.last_name as last_nam9_9_2_, user1_.password as passwor10_9_2_, user1_.structure_id as structu12_9_2_, user1_.username as usernam11_9_2_, structure2_.structure_id as structur1_6_3_, structure2_.nom_structure as nom_stru2_6_3_ from responses response0_ inner join users user1_ on response0_.user_id=user1_.user_id left outer join structure structure2_ on user1_.structure_id=structure2_.structure_id where response0_.ticket_id=?
Hibernate: select response0_.ticket_id as ticket_i4_5_0_, response0_.response_id as response1_5_0_, response0_.response_id as response1_5_1_, response0_.response as response2_5_1_, response0_.createDateTime as createda3_5_1_, response0_.ticket_id as ticket_i4_5_1_, response0_.user_id as user_id5_5_1_, user1_.user_id as user_id1_9_2_, user1_.email as email2_9_2_, user1_.etat as etat3_9_2_, user1_.phone as phone4_9_2_, user1_.currentAccessDate as currenta5_9_2_, user1_.dateExpiration as dateexpi6_9_2_, user1_.first_name as first_na7_9_2_, user1_.lastAccessDate as lastacce8_9_2_, user1_.last_name as last_nam9_9_2_, user1_.password as passwor10_9_2_, user1_.structure_id as structu12_9_2_, user1_.username as usernam11_9_2_, structure2_.structure_id as structur1_6_3_, structure2_.nom_structure as nom_stru2_6_3_ from responses response0_ inner join users user1_ on response0_.user_id=user1_.user_id left outer join structure structure2_ on user1_.structure_id=structure2_.structure_id where response0_.ticket_id=?
Hibernate: select response0_.ticket_id as ticket_i4_5_0_, response0_.response_id as response1_5_0_, response0_.response_id as response1_5_1_, response0_.response as response2_5_1_, response0_.createDateTime as createda3_5_1_, response0_.ticket_id as ticket_i4_5_1_, response0_.user_id as user_id5_5_1_, user1_.user_id as user_id1_9_2_, user1_.email as email2_9_2_, user1_.etat as etat3_9_2_, user1_.phone as phone4_9_2_, user1_.currentAccessDate as currenta5_9_2_, user1_.dateExpiration as dateexpi6_9_2_, user1_.first_name as first_na7_9_2_, user1_.lastAccessDate as lastacce8_9_2_, user1_.last_name as last_nam9_9_2_, user1_.password as passwor10_9_2_, user1_.structure_id as structu12_9_2_, user1_.username as usernam11_9_2_, structure2_.structure_id as structur1_6_3_, structure2_.nom_structure as nom_stru2_6_3_ from responses response0_ inner join users user1_ on response0_.user_id=user1_.user_id left outer join structure structure2_ on user1_.structure_id=structure2_.structure_id where response0_.ticket_id=?
Hibernate: select response0_.ticket_id as ticket_i4_5_0_, response0_.response_id as response1_5_0_, response0_.response_id as response1_5_1_, response0_.response as response2_5_1_, response0_.createDateTime as createda3_5_1_, response0_.ticket_id as ticket_i4_5_1_, response0_.user_id as user_id5_5_1_, user1_.user_id as user_id1_9_2_, user1_.email as email2_9_2_, user1_.etat as etat3_9_2_, user1_.phone as phone4_9_2_, user1_.currentAccessDate as currenta5_9_2_, user1_.dateExpiration as dateexpi6_9_2_, user1_.first_name as first_na7_9_2_, user1_.lastAccessDate as lastacce8_9_2_, user1_.last_name as last_nam9_9_2_, user1_.password as passwor10_9_2_, user1_.structure_id as structu12_9_2_, user1_.username as usernam11_9_2_, structure2_.structure_id as structur1_6_3_, structure2_.nom_structure as nom_stru2_6_3_ from responses response0_ inner join users user1_ on response0_.user_id=user1_.user_id left outer join structure structure2_ on user1_.structure_id=structure2_.structure_id where response0_.ticket_id=?
Hibernate: select response0_.ticket_id as ticket_i4_5_0_, response0_.response_id as response1_5_0_, response0_.response_id as response1_5_1_, response0_.response as response2_5_1_, response0_.createDateTime as createda3_5_1_, response0_.ticket_id as ticket_i4_5_1_, response0_.user_id as user_id5_5_1_, user1_.user_id as user_id1_9_2_, user1_.email as email2_9_2_, user1_.etat as etat3_9_2_, user1_.phone as phone4_9_2_, user1_.currentAccessDate as currenta5_9_2_, user1_.dateExpiration as dateexpi6_9_2_, user1_.first_name as first_na7_9_2_, user1_.lastAccessDate as lastacce8_9_2_, user1_.last_name as last_nam9_9_2_, user1_.password as passwor10_9_2_, user1_.structure_id as structu12_9_2_, user1_.username as usernam11_9_2_, structure2_.structure_id as structur1_6_3_, structure2_.nom_structure as nom_stru2_6_3_ from responses response0_ inner join users user1_ on response0_.user_id=user1_.user_id left outer join structure structure2_ on user1_.structure_id=structure2_.structure_id where response0_.ticket_id=?
Hibernate: select responses0_.user_id as user_id5_5_4_, responses0_.response_id as response1_5_4_, responses0_.response_id as response1_5_3_, responses0_.response as response2_5_3_, responses0_.createDateTime as createda3_5_3_, responses0_.ticket_id as ticket_i4_5_3_, responses0_.user_id as user_id5_5_3_, ticket1_.ticket_id as ticket_i1_8_0_, ticket1_.assigned_to as assigned2_8_0_, ticket1_.attachment_path as attachme3_8_0_, ticket1_.closed_by as closed_b4_8_0_, ticket1_.details as details5_8_0_, ticket1_.etat as etat6_8_0_, ticket1_.logiciel_id as logiciel7_8_0_, ticket1_.objet as objet8_8_0_, ticket1_.severity as severity9_8_0_, ticket1_.version_id as version10_8_0_, ticket1_.assignedDateTime as assigne11_8_0_, ticket1_.closedDateTime as closedd12_8_0_, ticket1_.createDateTime as created13_8_0_, ticket1_.user_id as user_id14_8_0_, user2_.user_id as user_id1_9_1_, user2_.email as email2_9_1_, user2_.etat as etat3_9_1_, user2_.phone as phone4_9_1_, user2_.currentAccessDate as currenta5_9_1_, user2_.dateExpiration as dateexpi6_9_1_, user2_.first_name as first_na7_9_1_, user2_.lastAccessDate as lastacce8_9_1_, user2_.last_name as last_nam9_9_1_, user2_.password as passwor10_9_1_, user2_.structure_id as structu12_9_1_, user2_.username as usernam11_9_1_, planificat3_.planif_id as planif_i1_4_2_, planificat3_.observation as observat2_4_2_, planificat3_.date_debut_planif as date_deb3_4_2_, planificat3_.date_debut_realise as date_deb4_4_2_, planificat3_.date_fin_planif as date_fin5_4_2_, planificat3_.date_fin_realise as date_fin6_4_2_, planificat3_.ticket_id as ticket_i7_4_2_ from responses responses0_ inner join tickets ticket1_ on responses0_.ticket_id=ticket1_.ticket_id left outer join users user2_ on ticket1_.user_id=user2_.user_id left outer join planification planificat3_ on ticket1_.ticket_id=planificat3_.ticket_id where responses0_.user_id in (select user4_.user_id from tickets ticket0_ cross join users user1_ cross join logiciel logiciel2_ cross join version version3_ inner join users user4_ on ticket0_.user_id=user4_.user_id where ticket0_.user_id=? and ticket0_.user_id=user1_.user_id and logiciel2_.logiciel_id=ticket0_.logiciel_id and ticket0_.version_id=version3_.version_id and ticket0_.etat<>'fermer' )
org.json.JSONException: JavaBean object contains recursively defined member variable of key "planification"
    at org.json.JSONObject.recursivelyDefinedObjectException(JSONObject.java:2722)
    at org.json.JSONObject.populateMap(JSONObject.java:1558)
    at org.json.JSONObject.<init>(JSONObject.java:372)
    at org.json.JSONObject.wrap(JSONObject.java:2496)
    at org.json.JSONObject.populateMap(JSONObject.java:1563)
    at org.json.JSONObject.<init>(JSONObject.java:372)
    at org.json.JSONObject.wrap(JSONObject.java:2496)
    at org.json.JSONObject.populateMap(JSONObject.java:1563)
    at org.json.JSONObject.populateMap(JSONObject.java:1530)
    at org.json.JSONObject.<init>(JSONObject.java:367)
    at org.json.JSONObject.wrap(JSONObject.java:2499)
    at org.json.JSONObject.wrap(JSONObject.java:2457)
    at org.json.JSONArray.addAll(JSONArray.java:1609)
    at org.json.JSONArray.<init>(JSONArray.java:176)
    at org.json.JSONObject.wrap(JSONObject.java:2478)
    at org.json.JSONObject.populateMap(JSONObject.java:1563)
    at org.json.JSONObject.populateMap(JSONObject.java:1530)
    at org.json.JSONObject.<init>(JSONObject.java:367)
    at org.json.JSONObject.wrap(JSONObject.java:2499)
    at org.json.JSONObject.wrap(JSONObject.java:2457)
    at org.json.JSONArray.addAll(JSONArray.java:1661)
    at org.json.JSONArray.<init>(JSONArray.java:228)
    at org.json.JSONObject.wrap(JSONObject.java:2481)
    at org.json.JSONObject.wrap(JSONObject.java:2457)
    at org.json.JSONArray.addAll(JSONArray.java:1609)
    at org.json.JSONArray.<init>(JSONArray.java:176)
    at org.json.JSONObject.put(JSONObject.java:1771)
    at com.myproject.helpdesk.controllers.TicketManagement.getTicketsByUser(TicketManagement.java:610)
    at com.myproject.helpdesk.controllers.TicketManagement.doGet(TicketManagement.java:95)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at com.myproject.helpdesk.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:33)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:196)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:698)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:366)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:639)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:847)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1680)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)

什么是 recursivelyDefinedObjectException?我的 Google 搜索总是指向递归和函数的主题,没有例外。

调试时,allTickets 列表包含 4 个对象,如下所示:

[
 [Ljava.lang.Object;@10e63606,
 [Ljava.lang.Object;@3c76d000,
 [Ljava.lang.Object;@5f5bfd07, 
 [Ljava.lang.Object;@3a14ab96
]

他是第一个对象的内容,例如:

[1455, test ticket, hello world, créé, Critique, 2022-02-03T15:48:41.058086, com.myproject.helpdesk.models.User@6f643c88, null, CTH, dummy, 10.1.1.v, null, null, 2022-02-03T15:48:41.058086, 2022-02-03T15:48:41.058086, CTH, CTH, email@something.com, 00999999999]

环境:

感谢任何帮助。

编辑:添加实体

获取 Tickets 列表是导致问题的原因。

门票

@Entity
@Table(name = "tickets")
public class Ticket implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ticket_id")
    private int ticket_id;

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false, insertable = true)
    private User user;
    
    @OneToMany(fetch = FetchType.EAGER,mappedBy="ticket")
    private List<Response> response;
    
     @OneToOne(mappedBy = "ticket")
     private Planification planification;

规划

@Entity
@Table(name = "planification")
public class Planification implements Serializable{
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "planif_id")
    private int planifId;

    @OneToOne
    @JoinColumn(name = "ticket_id",unique = true)
    private Ticket ticket;

用户

@Entity
@Table(name = "users")
public class User implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "user_id")
    private int user_id;

    @OneToMany(fetch = FetchType.EAGER ,mappedBy="user")
    @Fetch(value = FetchMode.SUBSELECT)
    private List<Ticket> tickets;
    
    @OneToMany(fetch = FetchType.EAGER ,mappedBy="user")
    @Fetch(value = FetchMode.SUBSELECT)
    private List<Response> responses;
    
    @ManyToOne(fetch = FetchType.EAGER ,cascade = CascadeType.ALL)
    @JoinColumn(name = "structure_id")
    private Structure structure;

回应

@Entity
@Table(name = "responses")
public class Response implements Serializable{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "response_id")
    private int responseId;
    
    @ManyToOne
    @JoinColumn(name = "ticket_id", nullable = false, insertable = true)
    private Ticket ticket;
    
    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false, insertable = true)
    private User user;

结构

@Entity
@Table(name = "structure")
public class Structure implements Serializable {
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "structure_id")
    private int structure_id;
    
    @OneToMany(mappedBy = "structure")
    private List<User> user;

编辑 2:

调试时我注意到 UserTicketStructure 有异常堆栈跟踪作为其 PersistentBag 的内容,

到底是什么原因造成的?!我检查了我的实体定义,它们对我来说没问题。

旁注

我的Ticket对象包含User对象,它包含Users的Tickets的列表,一直循环下去,无限递归,这正常吗?我的实体定义错了吗?我该如何解决这个问题?

你可以用地图。

Map<String,Object> mapObject = new HashMap<>();
List allTickets = ticketDao.getTicketsByUserDao(user);
mapObject.put("ticket",allTickets);

错误:

allTickets 列表包含一个无限递归的 User 对象,因此无法解析为 JSONObject

是什么原因造成的?

此查询:

Query query = session.createQuery(
        "SELECT T.id, T.Objet, T.Details, T.Etat,T.Severity, T.createDateTime, T.user, T.Attachment, U.lastName, L.nomLogiciel, V.nomVersion,T.AssignedTo,T.ClosedBy,T.closedDateTime,T.assignedDateTime, U.firstName, U.username, U.Email, U.Phone  FROM Ticket T, User U, Logiciel L, Version V "
        + "WHERE T.user= :user and T.user=U.user_id AND L.logiciel_id=T.Logiciel AND T.Version=V.version_id AND T.Etat!='fermer' ORDER BY T.createDateTime ")
        .setParameter("user", user);

这里强调T.user

Tickets table 中没有名为 User 的列,取而代之的是 user_id,因此 query.list() 方法返回了一个无限实例递归 User 对象而不是 user_id,它是一个 integer,* 我认为 *.

修复

T.user 更改为 T.user_id

现在可以将列表解析为 JSONObject,没有任何错误。

我看到你设法修复了它,但为了完整性我会添加另一个选项。我设法用两个简单的 类 重新创建了你的确切异常,它们的实例形成了一个循环引用,就像你的情况一样。

用户:

public class User {

    private long id;
    private Ticket ticket;

    public User(long id) {
        this.id = id;
    }

    //getters and setters
}

门票

public class Ticket {

    private long id;
    private User user;

    public Ticket(long id) {
        this.id = id;
    }

    //getters and setters
}

设置:

User user = new User(1);
Ticket ticket = new Ticket(2);
user.setTicket(ticket);
ticket.setUser(user);
List<User> users = Arrays.asList(user, user, user);

实例相互引用到无穷大,就像你的情况一样。这在 java 中完全有效,但在 json 中很难表示。根据我直接添加集合的测试,导致 Exception in thread "main" org.json.JSONException: JavaBean object contains recursively defined member variable of key "ticket".

JSONObject jsonObject = new JSONObject();
jsonObject.put("users", users);
System.out.println(jsonObject);

jsonObject.put(key, collection) 从集合创建 json 数组,但由于某些原因无法处理集合元素中的循环引用。

修复它的解决方法 是手动创建 JSONArray,然后迭代集合,手动添加每个元素 JSONArray。然后在JSONObject.

中添加准备好的json数组
JSONArray jsonArray = new JSONArray();
users.forEach(jsonArray::put);
JSONObject jsonObject = new JSONObject();
jsonObject.put("users", jsonArray);
System.out.println(jsonObject);