当我从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以获取默认的空构造函数。如果它不存在,则应添加它。

07-24 09:45
查看更多