打印多对多实体时出现异常

Posted

技术标签:

【中文标题】打印多对多实体时出现异常【英文标题】:Exception when printing out ManyToMany entity 【发布时间】:2022-01-23 18:16:14 【问题描述】:

我正在创建一个使用 Spring Data JPA 学习的简单项目。

我有这个实体(为清楚起见删除了 getter/setter):

@Entity
@Table(name = "shop")
@JsonIgnoreProperties("barbers")
public class Shop 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "idshop")
    private int shopID;

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

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

    //THIS SHOWS HOW MANY BARBERS WORKS IN THIS SHOP - CHILD
    @ManyToMany(mappedBy = "shops", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST, CascadeType.MERGE)
    private Set<Barber> barbers = new LinkedHashSet<>();

    public Set<Barber> getBarbers()

        return barbers;
    

    public void removeBarber(Barber barber)
    
        barbers.remove(barber);
        barber.getShops().remove(this);
    

    public void addBarber(Barber barber)
    
        barbers.add(barber);
        barber.getShops().add(this);
    

    public Shop() 
    

    public Shop(String name, String address) 
        this.name = name;
        this.address = address;
     this.address = address;
    

    @Override
    public String toString()
    
        return "Shop" +
                "id=" + shopID +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", barbers='" + barbers + '\'' +
                '';
    

我有一个简单的控制器,它可以很好地从存储库中获取请求的商店并将其返回。当我执行 System.out.println() 时,我可以看到以下内容:Shopid=3, name='fade', address='hammersmith', barbers='[Barberid=1, name='bob', rating='4']'

但是当控制器返回对象时,我得到以下异常:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.gogobarber.barber.entities.Shop$HibernateProxy$U83qWd1X["hibernateLazyInitializer"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.13.0.jar:2.13.0]
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1300) ~[jackson-databind-2.13.0.jar:2.13.0]
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400) ~[jackson-databind-2.13.0.jar:2.13.0]
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:46) ~[jackson-databind-2.13.0.jar:2.13.0]
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:29) ~[jackson-databind-2.13.0.jar:2.13.0]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.13.0.jar:2.13.0]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:774) ~[jackson-databind-2.13.0.jar:2.13.0]
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) ~[jackson-databind-2.13.0.jar:2.13.0]
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480) ~[jackson-databind-2.13.0.jar:2.13.0]

我有一个好主意,错误源于将 pojo 编组为 json 字符串,并且错误的原因很可能来自 Set&lt;Barber&gt;(尽管错误谈论没有找到 byteBuddy 的序列化程序.. 这是什么?)。通常总是配置杰克逊对象映射器吗?我假设杰克逊应该足够先进来解决一个集合?也许是因为我配置多对多关系的方式?

EDIT = 这是我的控制器和理发师课程:

@Entity
@Table(name = "barber")
@JsonIgnoreProperties("shops")
public class Barber 

public Barber() 


public Barber(String name, String rating) 
    this.name = name;
    this.rating = rating;


public int getBarberId() 
    return barberId;


public String getName() 
    return name;


public void setName(String name) 
    this.name = name;


public String getRating() 
    return rating;


public void setRating(String rating) 
    this.rating = rating;


public Set<Shop> getShops() 
    return shops;


//THIS FETCHES THE SHOPS THE BARBER IS ASSOCAITED TO - PARENT
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST, CascadeType.MERGE)
@JoinTable(name = "barberworkinshops",
        joinColumns = @JoinColumn(name = "Barber_ID", referencedColumnName = "idbarber"),
        inverseJoinColumns = @JoinColumn(name = "Shop_ID", referencedColumnName = "idshop")
)
private Set<Shop> shops = new LinkedHashSet<>();;

public void addBarberToShop(Shop shop)

    shops.add(shop);
    shop.getBarbers().add(this);


public void removeBarberFromShop(Shop shop)

    shops.remove(shop);
    shop.getBarbers().remove(this);


@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "idbarber")
private int barberId;

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

@Column(name = "Rating")
private String rating;

@Override
public String toString()

    return "Barber" +
            "id=" + barberId +
            ", name='" + name + '\'' +
            ", rating='" + rating + '\'' +
            ", shops='" + shops + '\'' +
            '';


控制器:

@RestController
public class ShopController 

@Autowired
private BarberRepo barberRepo;

@Autowired
private ShopRepo shopRepo;


@GetMapping("/shop/id")
public Shop getShop(@PathVariable String id)

    Shop shop = shopRepo.getById(Integer.valueOf(id));
    System.out.println(shop);
    return shop;


@PostMapping("/shop/name/address")
public Shop createShop(@PathVariable String name, @PathVariable String address)

    Shop shop = new Shop(name, address);
    return shopRepo.save(shop);


@PatchMapping("/shop/sId/addBarber/bId")
public Shop addBarber(@PathVariable String sId, @PathVariable String bId)

    Shop shop = shopRepo.getById(Integer.valueOf(sId));
    Barber b = barberRepo.getById(Integer.parseInt(bId));
    shop.addBarber(b);
    Shop save = shopRepo.save(shop);
    return save;


【问题讨论】:

尝试在 Set 之前添加 @JsonIgnoreProperties("hibernateLazyInitializer", "handler") 请添加最小代码以重现,Barberc lass 和 YourController ... @ZakirHussain - 试过了,没用。还是一样的异常 @HuyNguyen - 已编辑。问题现在有理发师和控制器 【参考方案1】:

据我所知,您在 Shop 实体中使用延迟加载来收集理发师...

如果从事务中取出或者通过jackson序列化可能会有问题...

我建议你可以做一些事情来避免控制台日志中的错误。

1- 在服务中加载理发师收藏,我个人想创建更多的服务层来与 DB Repo 层交互,你可以创建 ShopService 来管理它,你可以通过简单的方法强制加载: shop.getBarbers().size(); // 强制在同一个事务中获取实体

2- 为每个实体添加@JsonIgnoreProperties("hibernateLazyInitializer", "handler")

@JsonIgnoreProperties("hibernateLazyInitializer", "handler")

3- 设置 jackson 选项 fail-on-empty-beans=false。

spring.jackson.serialization.fail-on-empty-beans=false    

ObjectMapper objectMapper = new ObjectMapper();
    mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

【讨论】:

以上是关于打印多对多实体时出现异常的主要内容,如果未能解决你的问题,请参考以下文章

保持多对多关系时出现 PropertyAccessException

向核心数据添加记录时出现 NSSet 错误(多对多关系)

实体框架多对多关系错误

实体框架多对多异常与继承

尝试创建多对多关系时出现 MySQL 错误

Json序列化,有多对一和多对多关系时出现的问题