我有两个实体-以一对一单向关系连接的Concert和ConcertDetail(一个Concert具有一个细节)。
java - Java Spring Boot REST API-补丁-“java.util.LinkedHashMap无法转换为xxx”-LMLPHP

@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);
    }


如果我想更新艺术家,城市或地方等字段,则可以正常工作。
但是,当我将ConcertDetail作为JSON传递来更新给定的Concert时,我得到了以下异常:

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]


我在RestController中的Patch方法:

@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:
java - Java Spring Boot REST API-补丁-“java.util.LinkedHashMap无法转换为xxx”-LMLPHP

我已经尝试过Spring REST and PATCH method

最佳答案

控制器方法updatePartOfConcert使用一个Map<String, Object>参数,因此您没有告诉Spring将对象反序列化为哪种类型。结果,它也不能反序列化子属性:将上面在JSON响应中看到的concertDetail对象序列化为ConcertDetail对象是否正确?这三个字段还可以反序列化为一个实例的其他可能的类吗?

Spring不知道这一点,因此updates.get("concertDetail")将是包含更新后的Concert-details字段的Map

如果您总是一次更新整个ConcertDetail实例,则可以考虑使用Jackson ObjectMapperMap转换为ConcertDetail对象。参见例如this question

但是,如果您只想更新Concert详细信息的某些字段(鉴于您正在使用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"));
    }

10-04 14:02