我在为 /events URL 点赞执行 POST 时收到错误消息"Cannot construct instance of"消息



我正在测试一个REST API,并在Maven中使用spring-bot-starter-data-REST。MySQL数据库服务器中存在一个id为1的现有Organizer数据。我想将现有的组织者链接到场地。

ID  NAME            CREATED
1   Thomas Burgers  2021-05-31 12:58:18

Postman中的REST URL

http://localhost:8081/events-api-project/events

在Postman中,我将此POST请求发送到上面的REST URL

{
"name": "ABC",
"description": "Test Description",
"startTime": "2017-08-29T14:46:18Z",
"endTime": "2017-08-29T16:46:18Z",
"zoneId": "US/Central",
"organizer": "/organizers/1",
"venue": {
"name": "ABC XYZ",
"streetAddress": "12345",
"streetAddress2": "Spice Wood Springs",
"city": "Austin",
"state": "Texas",
"country": "United States",
"postalCode": "78750"
}
}

这是我在Postman中得到的回复

{
"cause": {
"cause": null,
"message": "Cannot construct instance of `com.dev.eventmanagement.entities.Organizer` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('/organizers/1')n at [Source: (org.apache.catalina.connector.CoyoteInputStream); line: 7, column: 18] (through reference chain: com.dev.eventmanagement.entities.Event["organizer"])"
},
"message": "JSON parse error: Cannot construct instance of `com.dev.eventmanagement.entities.Organizer` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('/organizers/1'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.dev.eventmanagement.entities.Organizer` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('/organizers/1')n at [Source: (org.apache.catalina.connector.CoyoteInputStream); line: 7, column: 18] (through reference chain: com.dev.eventmanagement.entities.Event["organizer"])"
}

组织者实体类

package com.dev.eventmanagement.entities;

import java.util.Objects;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.OneToMany;

@Entity
public class Organizer extends AbstractEntity {
private String name;

@OneToMany(mappedBy = "organizer")
private Set<Event> events;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Set<Event> getEvents() {
return events;
}

public void setEvents(Set<Event> events) {
this.events = events;
}

// important! override equals and hashcode
@Override
public boolean equals(Object obj) {

return Objects.equals(id, ((Organizer) obj).id);
}

@Override
public int hashCode() {
return Objects.hash(id);
}

public Long getResourceId() {
return this.id;
}
}

事件实体类

package com.dev.eventmanagement.entities;

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Objects;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

@Entity
public class Event extends AbstractEntity {

@Column(nullable = false)
private String name;

@Column(nullable = false)
private String description;

private ZonedDateTime startTime;

private ZonedDateTime endTime;

private ZoneId zoneId;

private boolean started;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(nullable = false)
private Organizer organizer;

@OneToMany(mappedBy = "event", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Participant> participants;

@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Venue venue;

public Venue getVenue() {
return venue;
}

public void setVenue(Venue venue) {
this.venue = venue;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public ZonedDateTime getStartTime() {
return startTime;
}

public void setStartTime(ZonedDateTime startTime) {
this.startTime = startTime;
}

public ZonedDateTime getEndTime() {
return endTime;
}

public void setEndTime(ZonedDateTime endTime) {
this.endTime = endTime;
}

public ZoneId getZoneId() {
return zoneId;
}

public void setZoneId(ZoneId zoneId) {
this.zoneId = zoneId;
}

public boolean isStarted() {
return started;
}

public void setStarted(boolean started) {
this.started = started;
}

public Organizer getOrganizer() {
return organizer;
}

public void setOrganizer(Organizer organizer) {
this.organizer = organizer;
}

public Set<Participant> getParticipants() {
return participants;
}

public void setParticipants(Set<Participant> participants) {
this.participants = participants;
}

// important! override equals and hashcode
@Override
public boolean equals(Object obj) {

return Objects.equals(id, ((Event) obj).id);
}

@Override
public int hashCode() {
return Objects.hash(id);
}

}

Organizer是一个类,而不是JSON中的String。如果您想使用这个类模型,您必须POST以下JSON:

{
"name": "ABC",
"description": "Test Description",
"startTime": "2017-08-29T14:46:18Z",
"endTime": "2017-08-29T16:46:18Z",
"zoneId": "US/Central",
"organizer": { "name": "/organizers/1" },
"venue": {
"name": "ABC XYZ",
"streetAddress": "12345",
"streetAddress2": "Spice Wood Springs",
"city": "Austin",
"state": "Texas",
"country": "United States",
"postalCode": "78750"
}
}

我怀疑这是否是您真正想要的,但如果您仔细阅读错误消息,这至少是异常的来源。如果你想接受你在这里显示的有效负载,你必须使用DTO。通常,人们只是使用id,而不是URL路径进行关联。但即便如此,你也需要特别小心,避免创建新的组织者,而是引用现有的组织者。总之,人们通常对此使用DTO,并将其映射到某个层中的实体。我认为这是Blaze Persistence实体视图的一个完美用例。

我创建了这个库,以便在JPA模型和自定义接口或抽象类定义模型之间进行简单的映射,比如类固醇上的Spring Data Projections。其思想是,您可以按照自己喜欢的方式定义目标结构(域模型(,并通过JPQL表达式将属性(getter(映射到实体模型。

使用Blaze Persistence实体视图,用例的DTO模型可能如下所示:

@EntityView(Event.class)
@CreatableEntityView
public interface EventDto {
@IdMapping
Long getId();
String getName();
void setName(String name);
String getDescription();
void setDescription(String description);
ZonedDateTime getStartTime();
void setStartTime(ZonedDateTime startTime);
ZonedDateTime getEndTime();
void setEndTime(ZonedDateTime endTime);
ZoneId getZoneId();
void setZoneId(ZoneId zoneId);
OrganizerIdDto getOrganizer();
void setOrganizer(OrganizerIdDto organizer);
VenueDto getVenue();
void setVenue(VenueDto venue);
@EntityView(Organizer.class)
interface OrganizerIdDto {
@IdMapping
Long getId();
}
@EntityView(Venue.class)
@CreatableEntityView
interface VenueDto {
@IdMapping
Long getId();
String getName();
void setName(String name);
String getStreetAddress();
void setStreetAddress(String streetAddress);
String getStreetAddress2();
void setStreetAddress2(String streetAddress2);
String getCity();
void setCity(String city);
String getState();
void setState(String state);
String getCountry();
void setCountry(String country);
String getPostalCode();
void setPostalCode(String postalCode);
}
}

保存Spring-WebMvc集成后,只需将对象传递到存储库即可:

@RequestMapping(path = "/events", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> updateCat(@RequestBody EventDto event) {
eventRepository.save(event);
return ResponseEntity.ok(event.getId().toString());
}

相关内容

  • 没有找到相关文章