0

Nous avons le démarrage de printemps avec elasticsearch et mysql. Nous avons une fonction pour réindexer toutes les données de MySQL dans ElasticSearch, qui est simple:Collection paresseuse dans Spring JPA avec Jackson et elasticsearch wihtout jsonignore

@Service 
@Transactional 
public class SearchIndexer { 

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

Maintenant, nous avons une entité appelée facture, qui a une collection chargée paresseux avec un calcul « dérivé »:

@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; 
    } 
} 

Lorsque le contrôleur de repos est utilisé, le json résultant contient correctement une propriété "allSimple". C'est parce que nous exécutons cela avec hibernate5module en une seule transaction.

Toutefois, lorsque nous appelons elasticsearchRepository.save(jpaRepository.findAll()) (également dans une transaction), le mappeur d'objet pour elasticsearch ne peut pas sérialiser la propriété "allSimple", en raison d'un LazyInitializationException. Le ElasticSearch-objectmapper est configuré comme suit:

@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); 
    } 
} 

Le hibernate5module est chargé et enregistré, mais n'a pas résolu le problème. Normalement, nous ajouterions un "JsonIgnore" à cette propriété, mais nous avons besoin de cette valeur, donc ce n'est pas une option. Des idées ?!

Répondre

0

J'ai eu un projet configuré avec ceci.

@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); 
    } 

} 

Si vous utilisez le démarrage de printemps, déclarant la MappingJackson2HttpMessageConverter de haricots et de l'enregistrement de la hibernate5module devrait résoudre votre problème.

Je pourrais rendre une entité à travers un contrôleur de repos.

+0

J'ai déjà un MappingJackson2HttpMessageConverter, mais cela est utilisé pour les contrôleurs de repos (comme je le disais, ceux-ci fonctionnent sans problèmes) et non utilisé par elasticsearch ... – Indivon

+0

pourriez-vous mettre à jour votre question et ajouter où vous utilisez le elasticsearchRepository. save (jpaRepository.findAll()) ?. –

+0

l'a mis à jour - il s'agit d'une seule méthode dans une classe de service, appelée par un point de terminaison – Indivon