我今天遇到了个bug,有关POJO双向绑定,一对多,多对一的JSON序列化bug。
环境:
系统:MacOS
服务器:Wildfly
框架:Quarkus
数据库:PostgreSQL
ORM框架:JPA (Hibernate实现)
JSON序列化框架:JSONB(Jackson实现)
我有表分别为customers
和orders
-- customers 表
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
name VARCHAR(30) NOT NULL
);
-- orders 表
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
order_time DATE DEFAULT NOW(),
customer_id INT,
FOREIGN KEY (customer_id) REFERENCES customers (id)
);
POJO
@Getter
@Entity
@Table(name="customers")
@NamedQuery(name="Customer.findAll", query="SELECT c FROM Customer c")
public class Customer implements Serializable {
@JsonbProperty
@Id
@GeneratedValue
int id;
@JsonbProperty
@Column
String name;
@JsonbProperty
@OneToMany(mappedBy="customer", cascade=CascadeType.ALL, fetch=FetchType.LAZY, orphanRemoval=true)
List<Order> orders;
}
@Getter
@Entity
@Table(name="orders")
public class Order implements Serializable {
@JsonbProperty
@Id
@GeneratedValue
int id;
@JsonbProperty
@Temporal(TemporalType.DATE)
@Column(name="order_time")
Date orderTime;
@JsonbProperty
@ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
@JoinColumn(name="customer_id", referencedColumnName="id")
Customer customer;
}
DAO层
@ApplicationScoped
public class CustomerService {
@PersistenceContext
private EntityManager em;
private static final Class<Customer> TYPE = Customer.class;
public Customer findById(Integer id)
return em.createNamedQuery("Customer.findById", TYPE)
.setParameter("id", id)
.getSingleResult();
}
}
AJAX层
@RequestScoped
@Path("/customer")
@Produces(MediaType.APPLICATION_JSON)
public class CustomerResource {
@Inject
private CustomerService dao;
@GET
@Path("{id}")
public Resopnse findById(@PathParam("id") Integer id) {
try {
return Response.ok(dao.findById(id)).build()
} catch (NoResultException e) {
return Response.status(404).build();
}
}
}
然后查询就报错了:
curl localhost:8080/customer/1
jakarta.json.bind.JsonbException: Recursive Reference found in …
就是循环引用,搞得我莫名其妙的。
我用的是@jakarta.persistence.OneToMany
,用法上可以这样双向绑定。肯定是Jsonb模块的错误。
解决方法:
删掉@jakarta.jsonb.annotation.JsonbProperty
然后就跑起来了