【问题标题】:Lazy collection in Spring JPA with Jackson and elasticsearch wihtout jsonignore使用 Jackson 和 elasticsearch 的 Spring JPA 中的懒惰收集,但没有 jsonignore
【发布时间】:2018-01-31 17:13:27
【问题描述】:

我们有带有 elasticsearch 和 mysql 的 spring boot。我们有一个功能可以将 mysql 中的所有数据重新索引到 elasticsearch 中,这很简单:

@Service
@Transactional
public class SearchIndexer {

    public void reindex(){
        elasticsearchRepository.save(jpaRepository.findAll());
    }
}

现在我们有一个名为 invoice 的实体,它有一个带有“派生”计算的延迟加载集合:

@Entity
@Table(name = "invoice")
@Document(indexName = "invoice")
public class Invoice implements Serializable {

     //... other props

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "invoice")
    @JsonIgnore
    private Set<InvoiceItem> invoiceItems = new LinkedHashSet<>();

    // getter and setters for invoiceItems

    public boolean isAllSimple() {
        if(getInvoiceType()==null){
            return false;
        }
        if(getInvoiceItems()==null){
            return false;
        }
        for(InvoiceItem item : getInvoiceItems()){
            if(!item.isSimple()){
                return false;
            }
        }
        return true;
    }
}

使用 rest-controller 时,生成的 json 正确地包含一个属性“allSimple”。这是因为我们在一个事务中使用 hibernate5module 运行它。

但是,当我们调用elasticsearchRepository.save(jpaRepository.findAll())(也在事务中)时,elasticsearch 的对象映射器无法序列化“allSimple”属性,因为LazyInitializationException。 elasticsearch-objectmapper配置如下:

@Bean
public ElasticsearchTemplate elasticsearchTemplate(Client client, Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder, Hibernate5Module hibernate5Module) {       
    return new ElasticsearchTemplate(client, new CustomEntityMapper(jackson2ObjectMapperBuilder.createXmlMapper(false).modulesToInstall(hibernate5Module).build()));        
}

public class CustomEntityMapper implements EntityMapper {

    private ObjectMapper objectMapper;

    public CustomEntityMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;    
        objectMapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);     
        objectMapper.configure( DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
    }        

    @Override
    public String mapToString(Object object) throws IOException {
        return objectMapper.writeValueAsString(object);
    }

    @Override
    public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
        return objectMapper.readValue(source, clazz);
    }
}

hibernate5module被加载注册了,但是没有解决问题。 通常我们会为该属性添加一个“JsonIgnore”,但我们需要该值,所以这不是选项。 有什么想法吗?!

【问题讨论】:

    标签: json spring hibernate spring-data-jpa spring-data-elasticsearch


    【解决方案1】:

    我有一个用这个配置的项目。

    @EnableWebMvc
    @Configuration
    @ComponentScan(basePackages = "com.sagasoftware.tracker.*")
    public class WebConfiguration extends WebMvcConfigurerAdapter {
        @Bean
        public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    
            MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
    
            ObjectMapper objectMapper = new ObjectMapper();
            Hibernate5Module hibernate5Module = new Hibernate5Module();
    
            objectMapper.registerModule(hibernate5Module);
            objectMapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
     objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
    
            messageConverter.setObjectMapper(objectMapper);
    
            return messageConverter;
        }
    
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            converters.add(mappingJackson2HttpMessageConverter());
            super.configureMessageConverters(converters);
        }
    
    }
    

    如果您使用的是 spring boot,则声明 bean MappingJackson2HttpMessageConverter 并注册 hibernate5module 应该可以解决您的问题。

    我可以通过一个休息控制器来渲染一个实体。

    【讨论】:

    • 我已经有一个 MappingJackson2HttpMessageConverter,但这用于休息控制器(正如我所说,这些控制器工作没有问题)并且不被 elasticsearch 使用...
    • 您能否更新您的问题并添加您使用 elasticsearchRepository.save(jpaRepository.findAll()) 的位置?。
    • 更新了它 - 它只是服务类中的一种方法,由休息端点调用
    猜你喜欢
    • 2016-10-07
    • 1970-01-01
    • 2016-07-03
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    相关资源
    最近更新 更多