在将对象转换为json

时间:2017-12-18 11:32:21

标签: java json hibernate spring-boot jackson

我是Spring的新手,在从与其他表有关系的表中获取记录时会出现这种懒惰的初始化错误。 我在网上看了很多但没有采取适当的方法。

表1:

@SuppressWarnings("serial")
@Entity
public class Terminal extends BaseEntity {

@Column(length = 100, unique = true)
private String shortName;

@Column
private short number; // short stores up to 32767 value

@Column
private String description;     

@OneToMany
@JoinColumn(name = "terminal_id", referencedColumnName = "uuid")
@Cascade({ CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DELETE })
private Set<BusinessHour> businessHour;

 public String getShortName() {
    return shortName;
}

public void setShortName(String shortName) {
    this.shortName = shortName;
}

public short getNumber() {
    return number;
}

public void setNumber(short number) {
    this.number = number;
}

public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}
public Set<BusinessHour> getBusinessHour() {
    return businessHour;
}

public void setBusinessHour(Set<BusinessHour> businessHour) {
    this.businessHour = businessHour;
}

表2:

@SuppressWarnings("serial")
@Entity
public class BusinessHour extends BaseEntity {

@Column
private DayOfWeek dayOfWeek;

@Column
private LocalTime startOfOperation;

@Column
private LocalTime endOfOperation;

public DayOfWeek getDayOfWeek() {
    return dayOfWeek;
}
}

服务代码:

@Service
public class TerminalServiceImpl implements TerminalService {

@Autowired
TerminalRepository terminalRepository;


    Iterable<Terminal> allTerminals = terminalRepository.findAll();
    List<Terminal> terminalList =  new ArrayList<Terminal>();
    for (Terminal terminal : allTerminals) {
        terminalList.add(terminal);
    }
    return terminalList;
}

终端存储库代码:

@Transactional
public interface TerminalRepository extends CrudRepository<Terminal, Long> {
}

调试期间出错的代码:

private List<Terminal> updateTerminalList() {
    List<Terminal> allTerminals = terminalService.fetchAllTerminal();
    return allTerminals;
}

public void terminalWrapperRun() {
    try {
       Payload payload = createTerminalPayload(applicationId);
        String json3 = object2Json(payload);
        kafkaRESTUtils.sendServerPayload(json3);
    } catch (Exception e1) {
        e1.printStackTrace();
    }
}

 public String object2Json(Object dataArray) throws JsonProcessingException {
    return mapper.writeValueAsString(dataArray);
}

错误:

com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: terminal.model.Terminal.businessHour, could not initialize proxy - no Session (through reference chain: 

将获取对象转换为json时获取异常。我发现由于代理对象返回由于提取类型懒惰(我希望保持原样)。

3 个答案:

答案 0 :(得分:0)

我认为此问题与您的ORM默认情况下LAZY加载集合有关。

@OneToMany
@JoinColumn(name = "terminal_id", referencedColumnName = "uuid")
@Cascade({ CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DELETE })
private Set<BusinessHour> businessHour;

@OneToMany注释有一个fetch属性,默认设置为LAZY。

FetchType fetch() default LAZY;

OneToMany reference

这意味着只有在访问数据时才会加载它。对于您的示例,当您尝试创建JSON字符串时会发生这种情况。但是,到目前为止,您不在ORM会话的范围内,因此它不知道如何加载数据。

因此您有2个选项。

  1. 更改注释以急切加载数据(这意味着BusinessHour Set将与父对象同时加载

    @OneToMany(fetch = FetchType.EAGER)

  2. 在ORM会话中执行JSON生成(我只是建议这样做是第一个导致性能问题的选项)。

答案 1 :(得分:0)

如果我没记错的话,这是EntityEntityManager使用时与Proxy分离造成的错误(即@OneToMany(fetch = FetchType.EAGER) ... private Set<BusinessHour> businessHour; ,它无法执行数据库查询以检索数据)。

您可以使用:

<div class="container">
    <p class="source-text">Hello world</p>
</div>
<ul class="list"></ul>

答案 2 :(得分:0)

使用FetchType = EAGER意味着针对您的实体的任何查询都会加载一大堆带注释的实体。

Imho,如果您100%确定您的实体仅用于您的特殊商业案例,这只是一个明智的行动。

在所有其他情况下 - 比如将数据编程为库,或者在实体上接受不同类型的查询,您应该使用实体图(https://docs.oracle.com/javaee/7/tutorial/persistence-entitygraphs002.htm)或显式加载(Hibernate.initialize,join-fetch ,例如参见https://vladmihalcea.com/hibernate-facts-the-importance-of-fetch-strategy/)。

如果您的用例仅是转换,那么您有两个不错的选择:

  • 在Transactional方法中将您的实体转换为JSON(如PillHead建议的那样)
  • 使用事务中所需的所有实体(通过实体图或Hibernate.initialize)显式加载您的实体,然后转换为您需要的JSON。