RestController: возвращение Resource <> заставляет FetchType.LAZY вести себя как FetchType.EAGER - PullRequest
1 голос
/ 04 октября 2019

У меня ниже сопоставления как Company, имеющие 1:N отношение с CompanyFunds

@Entity
public class Company{

    @Id
    private Integer companyId;

    private String name;

    @OneToMany(mappedBy = "company")
    private List<CompanyFund> companyFunds;

}

@Entity
public class CompanyFunds{

    @Id
    private Integer fundId;

    private String name;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "company_id")
  private Company company;

}

Я использую Spring-data-Jpa для моего уровня персистентности, а ниже указаны методы контроллера и обслуживания:

//controller
@GetMapping(value = "/{companyId}")
public Resource<Company> find(@PathVariable Integer companyId) {

  Resource<Company> companyResource = companyService.find(companyId);
  return companyResource;
}

//service
public Resource<CompanyTypeOther> find(Integer companyId) {
  Company company =  companyRepository.findById(companyId);

  return restResourceAssembler.toResource(company);
}


@Component
public class RestResourceAssembler implements ResourceAssembler<T, Resource<T>> {

    private EntityLinks entityLinks;

    public RestResourceAssembler(EntityLinks entityLinks) {
        this.entityLinks = entityLinks;
    }

    @Override
    public  Resource<T>  toResource(T entity) {
        Resource<T> resource = new Resource<>(entity);
        resource.add(entityLinks.linkToSingleResource(entity.getClass(), entity.getId()).withSelfRel());

        return resource;
    }
}

Теперь странно то, что до тех пор, пока return companyResource; (в контроллере) не будет выполнено, companyResource содержит null для companyFunds, т.е. загрузка LAZY работает нормально до тех порточка. Но в тот момент, когда выполняется return companyResource;, что-то идет внутри Spring, и оператор Select для CompanyFund запускается. Я отладил шаги, и ниже приведен код (try блок), ответственный за это:

public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {

  ......

  public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
    ........other code
    try {
      this.returnValueHandlers.handleReturnValue(
          returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
      if (logger.isTraceEnabled()) {
        logger.trace(formatErrorForReturnValue(returnValue), ex);
      }
      throw ex;
    }
  }

  .....

}

В сущностях не объявлено toString(), также не вызывается getCompanyFund(). Не могу понять, что Spring делает с returnValue выше, так что некоторые геттеры (или что-то) вызывают.

Еще одна вещь, которую я заметил, - эта проблема возникает, только когда возвращается Resource<Company>,Если я верну Company с контроллера, ничего неожиданного не произойдет. Ленивая загрузка работает нормально.

1 Ответ

0 голосов
/ 04 октября 2019

Так как я хочу лениво загрузить объект, небольшое исправление / хак решило проблему для меня (на данный момент).

@JsonIgnore
@OneToMany(mappedBy = "company")
private List<CompanyFund> companyFunds;

@JsonIgnore предотвращает сериализацию загруженного объекта LAZY. Так что я думаю, что Джексон является виновником здесь.

Это не исправление, на мой взгляд, а просто хак, чтобы сделать вещь . Все еще жду ответа от команды Spring.

...