Spring JPA中的懒惰集合与杰克逊和弹性搜索没有jsonignore

时间:2017-08-23 08:12:37

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

我们有springsearch和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())时(也在事务中),弹性搜索的objectmapper无法序列化“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”,但我们需要该值,所以这不是选项。 有什么想法吗?!

1 个答案:

答案 0 :(得分:0)

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

@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应该可以解决你的问题。

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