Spring Data JPA - Adicionando um método em todos os repositórios
1. Visão geral
O Spring Data facilita muito o processo de trabalhar com entidades, definindo apenas interfaces de repositório. Eles vêm com um conjunto de métodos predefinidos e permitem a possibilidade de adicionar métodos personalizados em cada interface.
No entanto, se quisermos adicionar um método personalizado que está disponível em todos os repositórios, o processo é um pouco mais complexo. Então, é isso que vamos explorar aqui com Spring Data JPA.
Para obter mais informações sobre como configurar e usar Spring Data JPA, verifique nossos artigos anteriores:Guide to Hibernate with Spring 4eIntroduction to Spring Data JPA.
2. Definindo uma Interface de Repositório Base
Primeiro, precisamos criar uma nova interface que declare nosso método personalizado:
@NoRepositoryBean
public interface ExtendedRepository
extends JpaRepository {
public List findByAttributeContainsText(String attributeName, String text);
}
Nossa interface estende a interfaceJpaRepository para que possamos nos beneficiar de todo o comportamento padrão.
Você também notará que adicionamos a anotação@NoRepositoryBean. Isso é necessário porque, caso contrário, o comportamento padrão do Spring é criar uma implementação para todas as subinterfaces deRepository.
Aqui, queremos fornecer nossa implementação que deve ser usada, pois esta é apenas uma interface destinada a ser estendida pelas interfaces DAO específicas da entidade real.
3. Implementando uma classe base
A seguir, forneceremos nossa implementação da interfaceExtendedRepository:
public class ExtendedRepositoryImpl
extends SimpleJpaRepository implements ExtendedRepository {
private EntityManager entityManager;
public ExtendedRepositoryImpl(JpaEntityInformation
entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
}
// ...
}
Esta classe estende a classeSimpleJpaRepository, que é a classe padrão que o Spring usa para fornecer implementações para interfaces de repositório.
Isso requer que criemos um construtor com os parâmetrosJpaEntityInformationeEntityManager que chama o construtor da classe pai.
Também precisamos da propriedadeEntityManager para usar em nosso método personalizado.
Além disso, temos que implementar o método personalizado herdado da interfaceExtendedRepository:
@Transactional
public List findByAttributeContainsText(String attributeName, String text) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery cQuery = builder.createQuery(getDomainClass());
Root root = cQuery.from(getDomainClass());
cQuery
.select(root)
.where(builder
.like(root.get(attributeName), "%" + text + "%"));
TypedQuery query = entityManager.createQuery(cQuery);
return query.getResultList();
}
Aqui, o métodofindByAttributeContainsText() procura todos os objetos do tipo T que possuem um atributo particular que contém o valorString dado como parâmetro.
4. Configuração JPA
Para dizer ao Spring para usar nossa classe personalizada em vez da classe padrão para construir implementações de repositório,we can use the repositoryBaseClass attribute:
@Configuration
@EnableJpaRepositories(basePackages = "org.example.persistence.dao",
repositoryBaseClass = ExtendedRepositoryImpl.class)
public class StudentJPAH2Config {
// additional JPA Configuration
}
5. Criando um Repositório de Entidades
A seguir, vamos ver como podemos usar nossa nova interface.
Primeiro, vamos adicionar uma entidadeStudent simples:
@Entity
public class Student {
@Id
private long id;
private String name;
// standard constructor, getters, setters
}
Então, podemos criar um DAO para a entidadeStudent que estende a interfaceExtendedRepository:
public interface ExtendedStudentRepository extends ExtendedRepository {
}
E é isso! Agora nossa implementação terá o métodofindByAttributeContainsText() personalizado.
Da mesma forma, qualquer interface que definirmos estendendo a interfaceExtendedRepository terá o mesmo método.
6. Testando o Repositório
Vamos criar um testeJUnit que mostra o método personalizado em ação:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { StudentJPAH2Config.class })
public class ExtendedStudentRepositoryIntegrationTest {
@Resource
private ExtendedStudentRepository extendedStudentRepository;
@Before
public void setup() {
Student student = new Student(1, "john");
extendedStudentRepository.save(student);
Student student2 = new Student(2, "johnson");
extendedStudentRepository.save(student2);
Student student3 = new Student(3, "tom");
extendedStudentRepository.save(student3);
}
@Test
public void givenStudents_whenFindByName_thenOk(){
List students
= extendedStudentRepository.findByAttributeContainsText("name", "john");
assertEquals("size incorrect", 2, students.size());
}
}
O teste usa o beanextendedStudentRepository primeiro para criar 3 registros de Aluno. Em seguida, o métodofindByAttributeContains() é chamado para localizar todos os alunos cujo nome contenha o texto “john”.
A classeExtendedStudentRepository pode usar os métodos padrão comosave()e o método personalizado que adicionamos.
7. Conclusão
Neste artigo rápido, mostramos como podemos adicionar um método personalizado a todos os repositórios no Spring Data JPA.
O código-fonte completo dos exemplos pode ser encontradoover on GitHub.