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 ?!
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
pourriez-vous mettre à jour votre question et ajouter où vous utilisez le elasticsearchRepository. save (jpaRepository.findAll()) ?. –
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