Hibernate Search / Lucene возвращает нулевые элементы, когда результатом является одна запись

Я столкнулся со странной проблемой с Hibernate Search и Lucene. Я считаю, что эта проблема довольно проста: когда я ищу что-то, что возвращает более одной записи, все работает нормально. Когда я ищу что-то, что возвращает только одну запись, тогда все элементы объекта равны нулю, но когда я вызываю метод toString(), там все есть.

Моя сущность:

import java.io.Serializable;
import java.sql.Blob;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.Store;

@Entity
@Indexed
@Table(name = "vw_colaborador", schema = "col")
public class Colaborador implements Serializable {

    private static final long serialVersionUID = 886370076152195975L;

    @Id
    @Column(name = "id", insertable = false, updatable = false)
    private Long id;

    @Column(name = "matricula", insertable = false, updatable = false)
    @Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
    private String matricula;

    @Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "nome", insertable = false, updatable = false)
    private String nome;

    @Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "email", insertable = false, updatable = false)
    private String email;

    @Column(name = "foto", insertable = false, updatable = false)
    private Blob foto;

    @Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "login", insertable = false, updatable = false)
    private String login;

    @Field(store = Store.YES, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "ramal", insertable = false, updatable = false)
    private String ramal;

    @Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "hierarquia_ua", insertable = false, updatable = false)
    private String ua;

    @Column(name = "situacao_id", insertable = false, updatable = false)
    private Long situacaoId;

    @Column(name = "situacao", insertable = false, updatable = false)
    private String situacao;

    @Column(name = "vinculo_id", insertable = false, updatable = false)
    private Long vinculoId;

    @Column(name = "vinculo", insertable = false, updatable = false)
    private String vinculo;

    @Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "diretoria", insertable = false, updatable = false)
    private String diretoria;

    @Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "sigla_diretoria", insertable = false, updatable = false)
    private String siglaDiretoria;

    @Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "sala", insertable = false, updatable = false)
    private String sala;

    @Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "predio", insertable = false, updatable = false)
    private String predio;

    //... getters and setters ommited

    @Override
    public String toString() {
    return "Colaborador [id=" + id + ", matricula=" + matricula + ", nome=" + nome + ", email=" + email + ", foto=" + foto + ", login=" + login + ", ramal=" + ramal + ", ua="
        + ua + ", situacaoId=" + situacaoId + ", situacao=" + situacao + ", vinculoId=" + vinculoId + ", vinculo=" + vinculo + ", diretoria=" + diretoria
        + ", siglaDiretoria=" + siglaDiretoria + ", sala=" + sala + ", predio=" + predio + "]";
    }
}

И мой DAO, где я ищу с помощью Hibernate Search ...

ColaboradorDAO (управляется Spring)

import java.util.List;

import javax.persistence.TypedQuery;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.jpa.Search;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.springframework.stereotype.Repository;

@Repository("colaboradorDAO")
public class ColaboradorDAO extends AbstractDAO<Colaborador, Long> {

    private static final Logger logger = LogManager.getLogger(ColaboradorDAO.class);

    @SuppressWarnings("unchecked")
    public List<Colaborador> filtrar(Object termo) throws DAOException {
    try {
        FullTextEntityManager fullTextEm = Search.getFullTextEntityManager(this.entityManager);
        QueryBuilder qb = fullTextEm.getSearchFactory().buildQueryBuilder().forEntity(Colaborador.class).get();

        Query query = qb.keyword()
            .onFields("matricula", "nome", "email", "login", "ramal", "ua", "diretoria", "siglaDiretoria", "sala", "predio")
            .matching(termo)
            .createQuery();

        FullTextQuery fullTextQuery = fullTextEm.createFullTextQuery(query);
        Sort sortField = new Sort(new SortField("nome", SortField.STRING));
        fullTextQuery.setSort(sortField);
        return fullTextQuery.getResultList();
    }
    catch (Exception e) {
        logger.error("Erro ao filtrar colaboradores com termo: " + termo, e);
        throw new DAOException(e);
    }
    }

    public void indexar() throws DAOException {
        FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(this.entityManager);

        try {
            fullTextEntityManager.createIndexer().startAndWait();
        }
        catch (InterruptedException e) {
            logger.error("Erro ao criar indice de busca dos colaboradores", e);
            throw new DAOException(e);
        }
    }
}

Когда я вызываю метод filtrar(String termo), он работает как шарм, без ошибок и исключений. Но когда результатом запроса является только одна запись, создается экземпляр объекта Colaborador, но все элементы равны null.

Пример:

@Test
public void testColaborador() {
    try {
        List<Colaborador> listColaborador = this.colaboradorService.filtrar("060091");
        for (Colaborador c : listColaborador) {
            System.out.println(c.getNome());
        }
    }
    catch (ServiceException e) {
        e.printStackTrace();
    }
}

Результат:

null

Если я изменю строку: System.out.println(c.getNome()); на System.out.println(c.toString());, тогда она отлично подойдет для печати всех элементов.

Я использую:

  • Hibernate Search 4.3.0.Final;
  • Hibernate Core 4.2.2.Final;
  • Весна 3.2.3.РЕЛИЗ;
  • Lucene 3.6.2;

Обновление моего вопроса:

Я обновил версию Hibernate Search до 4.4.0.Alpha1, и ошибка все еще сохраняется. Я также понял, что моя сущность связана с «ленивой загрузкой». Когда я проверяю свою сущность, все свойства равны нулю, но есть еще одно свойство с именем JavassistLazyInitializer.


person humungs    schedule 30.08.2013    source источник


Ответы (2)


Что ж, проблема решена! Я не могу использовать ключевое слово final для методов получения и установки для объекта. Когда я аннотировал геттеры вместо полей private, как сказал @Sanne, это сообщение об ошибке отображается на консоли:

ERROR PojoEntityTuplizer:201 - HHH000112: Getters of lazy classes cannot be final

Затем я удалил все последние ключевые слова моей сущности Colaborador и работает! Итак, я вернул аннотации к частным полям, и они все еще работают!

Спасибо!

person humungs    schedule 02.09.2013

Не подразумевает ли код, что c.getNome () имеет значение null? Вы проверили свои данные? Так ли это? Учитывая, что c.toString () работает, вы наверняка получите обратно сущность. Или вы говорите, что в представлении toString есть значение для nome?

person Hardy    schedule 01.09.2013
comment
Метод c.getNome() и все другие методы get возвращают null. Для меня это странная ошибка, потому что метод toString() правильно заполнен правильными данными. Как я уже сказал, это происходит только тогда, когда возвращается одна запись. Спасибо за Ваш ответ! - person humungs; 01.09.2013
comment
Когда нужно инициализировать только один объект, поиск использует другую стратегию, что действительно может вызвать некоторые странности в прокси-серверах Javassist. Не могли бы вы попробовать аннотировать геттеры вместо частных полей? - person Sanne; 02.09.2013
comment
@Sanne, спасибо тебе большое! Что ж, ваш ответ почти правильный. Действительно, это не расположение аннотаций, а ключевое слово final на getters и setters! Я такой глупый! Я удалил все final ключевые слова и, понял! Работает как шарм! Спасибо! - person humungs; 02.09.2013