英文:
SpringBoot: Cannot convert value of type 'java.lang.String' to required type 'java.util.Map' : no matching editors or conversion strategy found]]
问题
这个错误的原因是在前端的DTO(OrdinazioneDTO)的infoPiatto字段中,您的数据似乎是以字符串的形式而不是实际的Map对象传递的。确保在前端发送请求时,infoPiatto字段的数据是一个真实的Map对象,而不是一个字符串。您可以在前端调试确保正确地发送了数据,或者检查前端代码以确保在发送请求时传递了正确的Map对象。另外,您还可以查看后端控制器的接收参数类型是否与前端发送的数据类型匹配。
英文:
I'm developing a management software for resturant. I'm using Java Spring Boot for back end and JavaFX for the front end. I'm using Unirest library for the API REST.
I have an Ordination class (in my project called "Ordinazione").
This is the version in Front End:
package com.example.ratatouille23.Model;
import com.example.ratatouille23.Model.DTO.OrdinazioneDTO;
import java.util.HashMap;
import java.util.Map;
public class Ordinazione {
private String idTavolo;
private boolean evasa;
private Map<Piatto, InfoOrdine> infoPiatto;
public Ordinazione(String idTavolo){
this.idTavolo = idTavolo;
this.infoPiatto = new HashMap<>();
this.evasa = false;
}
public Ordinazione(){
infoPiatto = new HashMap<>();
}
public void incrementaQuantitaPiatto(Piatto piatto) {
if (infoPiatto.containsKey(piatto)){
InfoOrdine info = infoPiatto.get(piatto);
int quantity = info.getQuantity();
info.setQuantity(quantity+1);
infoPiatto.put(piatto, info);
} else {
InfoOrdine info = new InfoOrdine(1, StatoOrdine.DA_PREPARARE);
infoPiatto.put(piatto, info);
}
}
public void decrementaQuantitaPiatto(Piatto piatto) {
if (infoPiatto.containsKey(piatto)) {
InfoOrdine info = infoPiatto.get(piatto);
int quantity = info.getQuantity();
if (quantity>1){
info.setQuantity(quantity-1);
infoPiatto.put(piatto, info);
} else {
infoPiatto.remove(piatto);
}
}
}
public void aggiungiPiatto(Piatto piatto, int quantita) {
InfoOrdine info = new InfoOrdine(quantita, StatoOrdine.DA_PREPARARE);
infoPiatto.put(piatto, info);
}
public void setStatoInPreparazione(Piatto piatto){
InfoOrdine info = this.infoPiatto.get(piatto);
info.setStato(StatoOrdine.IN_PREPARAZIONE);
this.infoPiatto.put(piatto, info);
}
public void setStatoCompletato(Piatto piatto){
InfoOrdine info = this.infoPiatto.get(piatto);
info.setStato(StatoOrdine.COMPLETATO);
this.infoPiatto.put(piatto, info);
}
//
public String getIdTavolo() {
return idTavolo;
}
public void setIdTavolo(String idTavolo) {
this.idTavolo = idTavolo;
}
public Map<Piatto, InfoOrdine> getPiattiOrdinazione() {
return infoPiatto;
}
public boolean getStato() {
return evasa;
}
public boolean isEvasa() {
return evasa;
}
public void setEvasa(boolean evasa) {
this.evasa = evasa;
}
public Map<Piatto, InfoOrdine> getInfoPiatto() {
return infoPiatto;
}
public void setInfoPiatto(Map<Piatto, InfoOrdine> infoPiatto) {
this.infoPiatto = infoPiatto;
}
@Override
public String toString() {
return "Tavolo: " + idTavolo +
"\n\n" + infoPiatto;
}
// Inner classes
public class InfoOrdine{
private int quantity;
private StatoOrdine stato;
public InfoOrdine(int quantity, StatoOrdine stato) {
this.quantity = quantity;
this.stato = stato;
}
public InfoOrdine(int quantity){
this.quantity = quantity;
this.stato = StatoOrdine.DA_PREPARARE;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public StatoOrdine getStato() {
return stato;
}
public void setStato(StatoOrdine stato) {
this.stato = stato;
}
@Override
public String toString() {
return " x" + quantity + "\n";
}
}
public enum StatoOrdine{
DA_PREPARARE,
IN_PREPARAZIONE,
COMPLETATO;
}
}
This is OrdinazioneDTO:
package com.example.ratatouille23.Model.DTO;
import com.example.ratatouille23.Model.Ordinazione;
import com.example.ratatouille23.Model.Piatto;
import java.util.HashMap;
import java.util.Map;
public class OrdinazioneDTO {
private String idTavolo;
// private boolean evasa;
private Map<Piatto, Ordinazione.InfoOrdine> infoPiatto;
public OrdinazioneDTO(String idTavolo){
this.idTavolo = idTavolo;
this.infoPiatto = new HashMap<>();
// this.evasa = false;
}
public OrdinazioneDTO(){
infoPiatto = new HashMap<>();
}
// Getter and Setter here
@Override
public String toString() {
return "Tavolo: " + idTavolo +
"\n\n" + infoPiatto;
}
}
This is the Ordinazione's class in back end:
package com.springone3.demo.Entity;
import com.springone3.demo.Controller.PiattoController;
import jakarta.persistence.*;
import org.springframework.beans.factory.annotation.Autowired;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Entity
@Table
public class Ordinazione {
@Id
@SequenceGenerator(
name = "ordinazione_sequence",
sequenceName = "ordinazione_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "ordinazione_sequence"
)
private Long idOrdinazione;
private String idTavolo;
@OneToMany
Map<Piatto, InfoOrdine> infoPiatto;
private boolean evasa = false;
public Ordinazione(Long idOrdinazione, String idTavolo) {
this.idOrdinazione = idOrdinazione;
this.idTavolo = idTavolo;
this.infoPiatto = new HashMap<>();
}
public String getidTavolo() {
return idTavolo;
}
public void setidTavolo(String idTavolo) {
this.idTavolo = idTavolo;
}
public boolean isEvasa() {
return evasa;
}
public void setEvasa(boolean evasa) {
this.evasa = evasa;
}
public Ordinazione() {
}
public Long getIdOrdinazione() {
return idOrdinazione;
}
public void setIdOrdinazione(Long idOrdinazione) {
this.idOrdinazione = idOrdinazione;
}
public Map<Piatto, InfoOrdine> getInfoPiatto() {
return infoPiatto;
}
public void setInfoPiatto(Map<Piatto, InfoOrdine> infoPiatto) {
this.infoPiatto = infoPiatto;
}
public void aggiungiPiatto(Piatto piatto, Integer quantity) {
InfoOrdine info = new InfoOrdine(quantity, InfoOrdine.StatoOrdine.DA_PREPARARE);
infoPiatto.put(piatto, info);
}
@Override
public String toString() {
return "idTavolo: " + idTavolo +
"\n\n" + infoPiatto;
}
@Entity
@Table
public static class InfoOrdine {
@Id
private Long id;
@ManyToOne
@MapsId("idOrdinazione")
@JoinColumn(name = "id_ordinazione")
private Ordinazione ordinazione;
@ManyToOne
@MapsId("idPiatto")
@JoinColumn(name = "id_piatto")
private Piatto piatto;
private int quantity;
private InfoOrdine.StatoOrdine stato;
public InfoOrdine(int quantity, InfoOrdine.StatoOrdine stato) {
this.quantity = quantity;
this.stato = stato;
}
public InfoOrdine() {
}
// Getter and Setter here
@Override
public String toString() {
return " x" + quantity + "\n";
}
public enum StatoOrdine {
DA_PREPARARE,
IN_PREPARAZIONE,
COMPLETATO;
}
}
}
The DTO's version in back end is equal to front end.
When i call the confirm button in the front end, i call this method:
public void onBtnConfermaOrdinazioneClicked() {
// other code
OrdinazioneDTO ordinazioneDTO = new OrdinazioneDTO();
ordinazioneDTO.setIdTavolo(ordinazione.getIdTavolo());
ordinazioneDTO.setInfoPiatto(ordinazione.getInfoPiatto());
ordinazioneDAO.sendOrdinazione(ordinazioneDTO);
resetOrdinazione();
}
}
In front end i have this implementation of DAO'is interface for Ordinazione:
package com.example.ratatouille23.Model.DAO.DAOImplUnirest;
import com.example.ratatouille23.Model.DAO.DAOInterface.OrdinazioneDAO;
import com.example.ratatouille23.Model.DTO.OrdinazioneDTO;
import com.example.ratatouille23.Model.Ordinazione;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class OrdinazioneDAOImplUnirest implements OrdinazioneDAO {
// other code for methods
@Override
public void sendOrdinazione(OrdinazioneDTO ordinazione) {
try {
HttpResponse<JsonNode> response = Unirest.post("http://localhost:8080/api/v1/ordinazione/postOrdinazione")
.header("accept", "application/json")
.field("idTavolo", ordinazione.getIdTavolo())
.field("infoPiatto", ordinazione.getInfoPiatto())
.asJson();
System.out.println("InfoPiatto: " + ordinazione.getInfoPiatto());
} catch (UnirestException e) {
throw new RuntimeException(e);
}
}
This is the OrdinazioneController's backend:
package com.springone3.demo.Controller;
import com.springone3.demo.Entity.Categoria;
import com.springone3.demo.Entity.DTO.OrdinazioneDTO;
import com.springone3.demo.Entity.Ordinazione;
import com.springone3.demo.Service.OrdinazioneService;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping(path = "api/v1/ordinazione")
public class OrdinazioneController {
@Autowired
private final OrdinazioneService ordinazioneService;
@Autowired
private ModelMapper modelMapper;
public OrdinazioneController(OrdinazioneService ordinazioneService) {
this.ordinazioneService = ordinazioneService;
}
// other GET methods
@PostMapping(path = "/postOrdinazione")
public void sendOrdinazione(OrdinazioneDTO ordinazioneDaSalvare){
System.out.println("Il DTO è così: " + ordinazioneDaSalvare.getInfoPiatto());
Ordinazione ordinazione = modelMapper.map(ordinazioneDaSalvare, Ordinazione.class);
ordinazione.setEvasa(false);
System.out.println("L'entity è così: " + ordinazione.getInfoPiatto());
ordinazioneService.sendOrdinazione(ordinazione);
}
}
This is the Serice:
@Service
public class OrdinazioneService {
@Autowired
private final OrdinazioneRepository ordinazioneRepository;
@Autowired
private final InfoOrdineRepository infoOrdineRepository;
public OrdinazioneService(OrdinazioneRepository ordinazioneRepository, InfoOrdineRepository infoOrdineRepository) {
this.ordinazioneRepository = ordinazioneRepository;
this.infoOrdineRepository = infoOrdineRepository;
}
public void sendOrdinazione(Ordinazione ordinazione) {
ordinazioneRepository.save(ordinazione);
ArrayList<Piatto> listaPiatti = (ArrayList<Piatto>) ordinazione.getInfoPiatto().keySet();
ArrayList<Ordinazione.InfoOrdine> listaInfo = new ArrayList<>();
for(Piatto piatto: listaPiatti){
Ordinazione.InfoOrdine io = new Ordinazione.InfoOrdine();
io.setOrdinazione(ordinazione);
io.setPiatto(piatto);
io.setQuantity(io.getQuantity());
io.setStato(io.getStato());
listaInfo.add(io);
}
infoOrdineRepository.saveAll(listaInfo);
}
When i try to execute a post request in my GUI, this is the error that i obtain on back end side:
WARN 9248 --- [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public void com.springone3.demo.Controller.OrdinazioneController.sendOrdinazione(com.springone3.demo.Entity.DTO.OrdinazioneDTO): [Field error in object 'ordinazioneDTO' on field 'infoPiatto': rejected value [{Salmone= x1<EOL>}]; codes [typeMismatch.ordinazioneDTO.infoPiatto,typeMismatch.infoPiatto,typeMismatch.java.util.Map,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [ordinazioneDTO.infoPiatto,infoPiatto]; arguments []; default message [infoPiatto]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Map' for property 'infoPiatto'; Cannot convert value of type 'java.lang.String' to required type 'java.util.Map' for property 'infoPiatto': no matching editors or conversion strategy found]] ]
}
I really don't know how to resolve this. Any helps?
答案1
得分: 2
It seems that the Map object (infoPiatto) is not converted correctly when it is sent through Unirest .field()
.
我看到 Map 对象(infoPiatto)在通过 Unirest 的 .field()
发送时没有正确转换。
I believe that it probably is sent using toString on the Map which cannot be mapped to a converter on the server side.
我认为它可能是通过 Map 的 toString 方法发送的,这在服务器端无法映射到转换器上。
I think that using the DTO object directly is probably the best solution for you.
我认为直接使用 DTO 对象可能是你的最佳解决方案。
HttpResponse<JsonNode> response = Unirest.post("http://localhost:8080/api/v1/ordinazione/postOrdinazione")
.header("accept", "application/json")
.body(ordinazione)
.asJson();
在添加其中一个映射器之后,参见 http://kong.github.io/unirest-java/#object-mappers
英文:
It seems that the Map object (infoPiatto) is not converted correctly when it is sent through Unirest .field()
.
I believe that it probably is sent using toString on the Map which cannot be mapped to a converter on the server side.
I think that using the DTO object directly is probably the best solution for you
HttpResponse<JsonNode> response = Unirest.post("http://localhost:8080/api/v1/ordinazione/postOrdinazione")
.header("accept", "application/json")
.body(ordinazione)
.asJson();
after adding one of the mapper. See http://kong.github.io/unirest-java/#object-mappers
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论