当我从Page<Entity>
类中的方法返回@RestController
时,通过Entity
和@OneToXXX
引用的@ManyToXXX
的所有字段都在返回的JSON对象中发生。但是,当我将返回类型切换为PagedResource
(以便能够添加指向响应的链接)时,根本不包括@ManyToXXX
字段。
这是有问题的方法:
@GetMapping("/fetch")
public PagedResources getResults(Pageable pageable, PagedResourcesAssembler assembler) {
Page<ParentClass> page = myRepository.findAll(pageable);
PagedResources pagedResources = assembler.toResource(page, myResourceAssembler);
return pagedResources;
}
这是资源汇编程序:它是MyController主体中的
@Autowired
。MyResourceAssembler
@Component
public class MyResourceAssembler extends ResourceAssemblerSupport<ParentClass, Resource> {
public MyResourceAssembler() { super(MyController.class, Resource.class); }
@Override
public Resource toResource(ParentClass obj) {
return new Resource<>(obj,
linkTo(methodOn(MyController.class).getResults(obj.getId())).withRel("edit"),
}
}
这是基本的类定义:
家长班
@Entity
@Table(name = "parent_table", catalog = "myDB")
public class ParentClass implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;
@ManyToOne(optional = false)
@JoinColumn(name = "other_class", referencedColumnName = "id")
private OtherClass otherClass;
@OneToOne(mappedBy = "parent")
private SampleField1 sampleField1;
@OneToMany(mappedBy = "parent")
private List<SampleField2> sampleField2;
}
SampleField1 OneToXXX
@Entity
@Table(name = "sample_table_1", catalog = "myDB")
public class SampleField1 implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;
@Column(name="some_field")
String someField;
@OneToOne
@JoinColumn(name = "sample_field_1", referencedColumnName = "id")
@JsonBackReference //to avoid infinite recursion
private ParentClass parent;
}
其他类ManyToOne
@Entity
@Table(name = "other_table", catalog = "myDB")
public class OtherClass implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;
@Column(name="some_other_field")
String someOtherField;
// I don't need any reference to ParentClass here.
}
为了进一步解决此问题,这里是
changeProperties()
类中PersistentEntityJackson2Module
方法的日志输出:s.d.r.w.j.PersistentEntityJackson2Module : Assigning nested entity serializer for @javax.persistence.OneToOne(..) com.project.SampleField1 com.project.model.ParentClass.sampleField1
s.d.r.w.j.PersistentEntityJackson2Module : Assigning nested entity serializer for @javax.persistence.OneToMany(..) com.project.SampleField2 com.project.model.ParentClass.sampleField2
// .... omitted other lines for brevity
生成的JSON是:
{
"_embedded":{
"parentClasses":[
{
"id":1,
// <-- There is no field for otherClass !
"sampleField1":{
"id":1,
"sampleField":"blabla"
},
"sampleField2":[ ]
}
]
},
"links":[
]
}
从上面可以看出,
OneToXXX
字段被序列化,但是ManyToOne
字段没有输出,例如Assigning nested entity serializer for @javax.persistence.ManyToOne ... com.my.OtherClass ...
,因此响应JSON中不存在这些内容。根据this SO answer,将
@ManyToXXX
引用的实体作为链接附加到JSON响应。但这对我来说不是一个可以接受的解决方案,因为我对其他客户有不同的消费计划。底线是,我想在
ManyToOne
方法返回的JSON响应中包含getResults()
引用的实体。我可以提供的任何内容都可以在评论中提问。
最佳答案
在响应中返回实体不是最好的方法,因为通常客户端不需要整个数据集。此外,如果实体之间具有彼此的链接,则会在序列化尝试时导致StackoverflowException。使用DTO进行响应。至少它将帮助您确定问题出在哪里-序列化或从数据库获取。无论如何,这是将数据提供给客户端的更合适的方法。
顺便说一下,在ParentClass中检查otherClass的getter和setter :)如果threre不是getter和setter,那将是您遇到问题的原因。
另外,请查看OtherClass以获取默认的空构造函数。如果它不存在,则应添加它。