英文:
Why is deserialization with quarkus-panache, hibernate and jsonb failing?
问题
我想在使用 Hibernate、Panache 和 Quarkus 方面做一些尝试。我想要构建一个“追踪(tracing)”API,其中一个人可以拥有多个追踪,但一个追踪只能由一个人拥有。但是我遇到了反序列化错误。
假设我想要发送以下内容:
curl --location --request POST 'localhost:8080/trace' \
--header 'Content-Type: application/json' \
--data-raw '{
"traceOwner": "AtestOwner",
"participants": ["Karl", "John"],
"place": "10101, TestCity, TestStreet 25",
"startTime": "2016-07-20T23:07:41.907+02:00[Europe/Berlin]",
"stopTime": "2016-07-27T23:07:45.807+02:00",
"comment": "TestComment"
}'
我收到以下错误:
javax.ws.rs.ProcessingException: RESTEASY008200: JSON Binding deserialization error: javax.json.bind.JsonbException:
Unable to deserialize property 'traceOwner' because of: Error deserialize JSON value into type: class de.test.Person.
并且在日志中看到:
2020-07-27 10:48:12,597 SEVERE [org.ecl.yas.int.Unmarshaller] (executor-thread-1) Unable to deserialize property 'traceOwner' because of: Error deserialize JSON value into type: class de.test.Person.
我的实体类看起来像这样:
import java.time.ZonedDateTime;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
@Entity
public class Trace extends PanacheEntity {
@ManyToOne
public Person traceOwner;
@ElementCollection
public List<String> participants;
public String place;
@Column(columnDefinition = "TIMESTAMP WITH TIME ZONE")
public ZonedDateTime startTime;
@Column(columnDefinition = "TIMESTAMP WITH TIME ZONE")
public ZonedDateTime stopTime;
public String comment;
public String toString() {
return String.format("%s, [%s, %s], %s, %s, %s", this.traceOwner, this.participants.get(0),
this.participants.get(1), this.place, this.startTime, this.stopTime, this.comment);
}
}
和
import javax.persistence.Entity;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
@Entity
public class Person extends PanacheEntity {
public String name;
}
POST 端点看起来是这样的:
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response createTrace(@Valid Trace trace) {
try {
LOG.info(trace);
transaction.begin();
trace.persist();
transaction.commit();
} catch (NotSupportedException | SystemException | SecurityException | IllegalStateException | RollbackException
| HeuristicMixedException | HeuristicRollbackException e1) {
LOG.error("Could not finish transaction to save entity", e1);
return Response.status(HttpStatus.SC_BAD_REQUEST).build();
}
return Response.ok(Trace.find("startTime =?1 AND traceOwner = ?2", trace.startTime, trace.traceOwner).firstResult())
.build();
}
为了避免缓存问题,我打开了一个新的事务,但我猜这不是问题的原因?
我真的不明白为什么 JSONB 抱怨反序列化问题,以及我如何解决它。另外,在某个时候,我想让 public List<String> participants
成为 public List<Person> participants
,但在关系和反序列化正常工作后再进行修改。
英文:
I wanted to play around with hibernate, panache and quarkus a bit. I wanted to build a "tracing" api where a person can have several traces but a trace can only be owned by one person. but I am facing a deserialization error.
Let's say I want to post this:
curl --location --request POST 'localhost:8080/trace' \
--header 'Content-Type: application/json' \
--data-raw '{
"traceOwner": "AtestOwner",
"participants": ["Karl", "John"],
"place": "10101, TestCity, TestStreet 25",
"startTime": "2016-07-20T23:07:41.907+02:00[Europe/Berlin]",
"stopTime": "2016-07-27T23:07:45.807+02:00",
"comment": "TestComment"
}'
I get the following errors:
javax.ws.rs.ProcessingException: RESTEASY008200: JSON Binding deserialization error: javax.json.bind.JsonbException:
Unable to deserialize property &#x27;traceOwner&#x27; because of: Error deserialize JSON value into type: class
de.test.Person.
and in the logs:
2020-07-27 10:48:12,597 SEVERE [org.ecl.yas.int.Unmarshaller] (executor-thread-1) Unable to deserialize property 'traceOwner' because of: Error deserialize JSON value into type: class de.test.Person.
My Entities look like this:
import java.time.ZonedDateTime;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
@Entity
public class Trace extends PanacheEntity {
@ManyToOne
public Person traceOwner;
@ElementCollection
public List<String> participants;
public String place;
@Column(columnDefinition = "TIMESTAMP WITH TIME ZONE")
public ZonedDateTime startTime;
@Column(columnDefinition = "TIMESTAMP WITH TIME ZONE")
public ZonedDateTime stopTime;
public String comment;
public String toString() {
return String.format("%s, [%s, %s], %s, %s, %s", this.traceOwner, this.participants.get(0),
this.participants.get(1), this.place, this.startTime, this.stopTime, this.comment);
}
}
and
import javax.persistence.Entity;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
@Entity
public class Person extends PanacheEntity {
public String name;
}
The POST endpoint looks like this:
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response createTrace(@Valid Trace trace) {
try {
LOG.info(trace);
transaction.begin();
trace.persist();
transaction.commit();
} catch (NotSupportedException | SystemException | SecurityException | IllegalStateException | RollbackException
| HeuristicMixedException | HeuristicRollbackException e1) {
LOG.error("Could not finish transaction to save entity", e1);
return Response.status(HttpStatus.SC_BAD_REQUEST).build();
}
return Response.ok(Trace.find("startTime =?1 AND traceOwner = ?2", trace.startTime, trace.traceOwner).firstResult())
.build();
}
To avoid a caching problem I open a new transaction, but I guess that is not the problem?
I don't really get why jsonB complains about the deserialization and how I can fix it. Also, at some point I wanted public List<String> participants
to be public List<Person> participants
but that can wait till the relation and deserialization works.
答案1
得分: 2
所以,我发现我做错了两件事:
- 使用有效的 JSON:
curl --location --request POST 'localhost:8080/trace' \
--header 'Content-Type: application/json' \
--data-raw '{
"traceOwner": {"name": "AtestOwner"},
"participants": ["Karl", "John"],
"place": "10101, TestCity, TestStreet 25",
"startTime": "2016-07-20T23:07:41.907+02:00[Europe/Berlin]",
"stopTime": "2016-07-27T23:07:45.807+02:00",
"comment": "TestComment"
}'
请注意不同的 "traceOwner" 部分。
- 使用
@ManyToOne(cascade = CascadeType.ALL)
在持久化时也更新瞬态属性。
英文:
So, I found out what I did do wrong. Two things:
- Use a valid json:
curl --location --request POST 'localhost:8080/trace' \
--header 'Content-Type: application/json' \
--data-raw '{
"traceOwner": {"name": "AtestOwner"},
"participants": ["Karl", "John"],
"place": "10101, TestCity, TestStreet 25",
"startTime": "2016-07-20T23:07:41.907+02:00[Europe/Berlin]",
"stopTime": "2016-07-27T23:07:45.807+02:00",
"comment": "TestComment"
}'
Please notice the different "traceOwner" part.
- Use
@ManyToOne(cascade = CascadeType.ALL)
to also update the transient property when persisting.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论