如何不设置@RestResource(exported=false)向Spring Data Rest提交嵌套实体
问题原因
Spring Data Rest 对关联属性的反序列化有明确规则:引用已存在的关联实体时,必须传入该实体对应的资源URI(即self链接),直接传入嵌套的实体对象、完整的RepresentationModel包装对象都会被判定为「需要新增嵌套实体」,而非关联已存在实体,这也是你传RepresentationModel<Address>时报addressId为null的核心原因——框架试图把你传入的对象作为新Address解析,自然找不到必填的id字段。
可直接落地的解决方案
方案1:手动构造带URI的请求体(零侵入,不需要修改原有实体类)
不需要调整原有Student、Address的类定义,提交请求时直接把关联字段替换为对应资源的self链接即可,示例代码:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import org.springframework.hateoas.RepresentationModel; // 1. 调用接口获取已保存的Address资源(原有逻辑保留) RepresentationModel<Address> address = // feign调用获取Address的逻辑 // 2. 从返回的资源模型中提取self链接(就是SDR识别的关联URI) String addressSelfUri = address.getRequiredLink("self").getHref(); // 3. 构造提交的请求体 ObjectMapper objectMapper = new ObjectMapper(); ObjectNode studentPayload = objectMapper.createObjectNode(); studentPayload.put("name", "name"); studentPayload.put("address", addressSelfUri); // 关联字段直接传URI字符串 // 4. 提交请求 client.save(studentPayload);
方案2:自定义序列化规则(适配原有实体类传参逻辑)
如果你希望继续用student.setAddress(address.getContent())的原有写法,只需要给Student类的关联字段加自定义序列化器,让Jackson序列化时自动把Address实体转成对应的资源URI即可:
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.springframework.web.util.UriComponentsBuilder; class Student { private String name; // 加自定义序列化注解 @JsonSerialize(using = AddressUriSerializer.class) private Address address; // 省略getter/setter } // 自定义Address序列化器 class AddressUriSerializer extends com.fasterxml.jackson.databind.JsonSerializer<Address> { @Override public void serialize(Address address, com.fasterxml.jackson.core.JsonGenerator gen, com.fasterxml.jackson.databind.SerializerProvider serializers) throws java.io.IOException { if (address == null) { gen.writeNull(); return; } // 拼接SDR暴露的Address资源路径,和你GET查询Address的路径保持一致 String addressUri = UriComponentsBuilder .fromPath("/api/addresses/{id}") .buildAndExpand(address.getId()) .toUriString(); gen.writeString(addressUri); } }
配置完成后原来的调用逻辑不需要修改,Feign序列化时会自动把address字段转成SDR能识别的URI格式。
避坑说明
- 不要把关联字段类型改成
RepresentationModel<Address>:这个类型序列化后会同时输出实体内容和links数组,SDR不会自动从这个结构里提取关联URI,还是会尝试解析嵌套的Address实体,触发id为null的错误。- 传入的URI必须是SDR当前服务暴露的可访问资源路径,要和GET获取单条Address的请求路径完全一致,否则会抛出关联资源找不到的异常。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

