Java API REST Spring Boot - исправление - "java .util.LinkedHashMap не может быть приведен к xxx" - PullRequest
0 голосов
/ 29 марта 2020


У меня есть две сущности - Concert и ConcertDetail , соединенные в однонаправленной взаимосвязи One-to-One (один концерт имеет одну деталь).
enter image description here

@Entity
@Table(name = "concert")
public class Concert {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "artist")
    private String artist;

    @Column(name = "city")
    private String city;

    @Column(name = "place")
    private String place;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "concert_detail_id")
    private ConcertDetail concertDetail;

    public Concert() {
    }

    public Concert(String artist,
                   String city,
                   String place) {
        this.artist = artist;
        this.city = city;
        this.place = place;
    }
//skipping the setters and getters

@Entity
@Table(name = "concert_detail")
public class ConcertDetail {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "description")
    private String description;

    @Column(name = "date")
    private LocalDate date;

    @Column(name = "time")
    private LocalTime time;

    public ConcertDetail() {
    }

    public ConcertDetail(String description,
                         LocalDate date,
                         LocalTime time) {
        this.description = description;
        this.date = date;
        this.time = time;
    }
//skipping the setters and getters

Что не работает, так это частичное обновление с @PatchMapping.

@PatchMapping("/concerts/{id}")
    public ResponseEntity<Concert> updatePartOfConcert(@RequestBody Map<String,Object> updates,
                                                       @PathVariable("id") int id) {
        Concert concert = concertRepository.findById(id);
        if (concert == null) {
            System.out.println("Concert with id: " + id + " not found in the system!");
            return new ResponseEntity<Concert>(HttpStatus.NOT_FOUND);
        }
        partialUpdate(concert, updates);
        return new ResponseEntity<Concert>(HttpStatus.NO_CONTENT);
    }

    private void partialUpdate(Concert concert, Map<String,Object> updates) {
        if(updates.containsKey("artist")) {
            concert.setArtist((String) updates.get("artist"));
        }
        if(updates.containsKey("city")) {
            concert.setCity((String) updates.get("city"));
        }
        if(updates.containsKey("place")) {
            concert.setPlace((String) updates.get("place"));
        }
        if(updates.containsKey("concertDetail")) {
            concert.setConcertDetail((ConcertDetail) updates.get("concertDetail"));
        }
        concertRepository.save(concert);
    }

Если я хочу обновить такие поля, как artist, city или place - все работает нормально. Но когда я передаю КонцертДетейл как JSON для обновления данного Концерта с его помощью - я получаю следующее исключение:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.musicao.app.entity.ConcertDetail
    at com.musicao.app.restController.ConcertRestController.partialUpdate(ConcertRestController.java:109) ~[classes/:na]
    at com.musicao.app.restController.ConcertRestController.updatePartOfConcert(ConcertRestController.java:94) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_242]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_242]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_242]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_242]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE]

Метод My Patch в RestController :

@PatchMapping("/concerts/{id}")
    public ResponseEntity<Concert> updatePartOfConcert(@RequestBody Map<String,Object> updates,
                                                       @PathVariable("id") int id) {
        Concert concert = concertRepository.findById(id);
        if (concert == null) {
            System.out.println("Concert with id: " + id + " not found in the system!");
            return new ResponseEntity<Concert>(HttpStatus.NOT_FOUND);
        }
        partialUpdate(concert, updates);
        return new ResponseEntity<Concert>(HttpStatus.NO_CONTENT);
    }

    private void partialUpdate(Concert concert, Map<String,Object> updates) {
        if(updates.containsKey("artist")) {
            concert.setArtist((String) updates.get("artist"));
        }
        if(updates.containsKey("city")) {
            concert.setCity((String) updates.get("city"));
        }
        if(updates.containsKey("place")) {
            concert.setPlace((String) updates.get("place"));
        }
        if(updates.containsKey("concertDetail")) {
            concert.setConcertDetail((ConcertDetail) updates.get("concertDetail"));
        }
        concertRepository.save(concert);
    }

JSON Прохожу в Почтальоне:
enter image description here

Я уже пробовал Spring REST и PATCH метод

1 Ответ

1 голос
/ 29 марта 2020

Ваш метод контроллера updatePartOfConcert принимает параметр Map<String, Object>, поэтому вы не указываете Spring, к какому типу объекта его десериализовать. В результате он также не может десериализовать дочерние свойства: будет ли правильным корректировать сериализацию объекта concertDetail, показанного выше в вашем ответе JSON на объект ConcertDetail? Существуют ли другие возможные классы, которые эти три поля могут десериализовать для экземпляра?

Spring не может этого знать, поэтому updates.get("concertDetail") будет Map, который содержит обновленные поля сведений о концерте.

Если вы всегда обновляете весь экземпляр ConcertDetail в одном go, вы можете использовать Джексон ObjectMapper для преобразования Map в ConcertDetail объект. См., Например, этот вопрос .

Однако, если вы хотите обновить только некоторые поля детализации концерта (что вы можете сделать, учитывая, что вы используете запрос PATCH) затем вам потребуется написать отдельный метод для обновления этого:

private void partialUpdateConcertDetail(ConcertDetail concertDetail, Map<String, Object> detailUpdates) {
    if (detailUpdates.containsKey("description")) {
        concertDetail.setDescription((String) detailUpdates.get("description"));
    }

    // ... repeat for other fields.    
}

Затем вы вызываете этот метод из вашего partialUpdate метода:

    if (updates.containsKey("concertDetail")) {
        partialUpdateConcertDetail(concert.getConcertDetail(), (Map<String, Object>) updates.get("concertDetail"));
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...