Can i return a Stream from a spring jpa repository using a querydsl predicate argument - spring-data

I'm using spring data and have a repository that extends JpaRepository and QueryDslPredicateExecutor. I get a list of entities from the repository by calling the Iterable findAll(Predicate p) method. I was wondering, is it possible to get a Stream returned from the repository passing in a querydsl predicate as an argument?

as described in https://github.com/spring-projects/spring-data-commons/issues/1169#issuecomment-752400977, you can declare your own method that returns List<...>
import java.util.List;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import com.querydsl.core.types.Predicate;
#Repository
public interface MyEntityRepository extends MongoRepository<MyEntity, ObjectId>, QuerydslPredicateExecutor<MyEntity> {
List<MyEntity> findAll(Predicate predicate);
}
then simply
myEntityRepository.findAll(myPredicate).stream()....

I think it isn't possible right now. Check this issue: https://jira.spring.io/browse/DATACMNS-704

Related

Add custom database session variable to Spring Boot JPA queries?

I am trying to set SET SESSION encrypt.key='some_key' to database queries or connection.
Thing is I have following column definition in my model class
#ColumnTransformer(forColumn = "first_name",
read = "pgp_sym_decrypt(first_name, current_setting('encrypt.key'))",
write = "pgp_sym_encrypt(?, current_setting('encrypt.key'))")
#Column(name = "first_name", columnDefinition = "bytea")
private String firstName;
Above works when we set encrypt.key in postgres.conf file directly but out requirement is to have encrypt.key configurable from our spring properties file.
Things I tried.
AttributeConverter annotation with custom Converter class which only works with JPA, and LIKE operations are not supported.
I tried ContextEventListener where I executed SET SESSION query at application startup but that only works for few requests
Next I tried CustomTransactionManager extends JpaTransactionManager where I was doing following
#Override
protected void prepareSynchronization(DefaultTransactionStatus status,TransactionDefinition definition) {
super.prepareSynchronization(status, definition);
if (status.isNewTransaction()) {
final String query = "SET encrypt.key='" + encryptKey + "'";
entityManager.createNativeQuery(query).executeUpdate();
}
log.info("Encrypt Key : {}", entityManager.createNativeQuery("SElECT current_setting('encrypt.key')").getSingleResult());
}
}
Above does not work when I call normal JPA Repository methods and encrypt.key is not set as the CustomTransactionManager class in not called.
Any guidance in right direction would help me a lot
Since I created CustomTransactionManager extends JpaTransactionManager
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionStatus;
import javax.persistence.EntityManager;
#Component
#Slf4j
#Primary
#Qualifier(value = "transactionManager")
public class CustomTransactionManager extends JpaTransactionManager {
#Autowired
private EntityManager entityManager;
#Value("${database.encryption.key}")
private String encryptKey;
#Override
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
super.prepareSynchronization(status, definition);
if (status.isNewTransaction()) {
final String query = "SET SESSION encrypt.key='" + encryptKey + "'";
entityManager.createNativeQuery(query).executeUpdate();
}
}
}
Above was not getting called when I used normal JPA Repository methods.
For example,
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByFirstName(String firstName);
}
Adding #Transactional on Repository class did override framework logic where a shared transaction was getting created behind-the-scenes for all repository beans. This resulted in my CustomTransactionManager to be called even with repository methods.
I initially thought that adding Transactional annotation was overkill but found out that it gets created automatically at framework level as well so manually adding it had no additional footprint on its own but code/query you write inside CustomTransactionManager class will add required request footprint.
So I ended up adding #Transactional annotation on all repository classes whose domain(table) had encrypted columns.
For my use-case, this was the most flexible solution to have column level encryption on Azure postgres datbase service with Spring boot because we can not add custom environment variables there from Azure Portal, and directly adding to postgres.conf file also not possible due it being a SAAS service.

How to use Rest Service while using Spring Boot & Spring Data Jpa

Im working on a spring boot application for rest service with using spring data jpa. I followed instructors and read much answers but I couldn't fix my rest service.
Here is application.class
package tr.kasim.Application;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
#EnableJpaRepositories("tr.kasim.Dao")
#EntityScan("tr.kasim.Model")
#ComponentScan({"tr.kasim.Service", "tr.kasim.Application" })
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Here is `restcontroller.class
package tr.kasim.Controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import tr.kasim.Service.PersonelService;
import tr.kasim.Model.Personel;
#RestController
public class STRestController {
#Autowired
public PersonelService personelService;
#RequestMapping(value = "/api/personels", method = RequestMethod.GET)
public ResponseEntity<List<Personel>> getPersonels(){
List<Personel> personels = personelService.findAll();
return ResponseEntity.ok().body(personels);
}
}
`
Here is Service.class`
package tr.kasim.Service;
import java.util.List;
import tr.kasim.Model.Personel;
public interface PersonelService {
List<Personel> findAll();
}
`
Here is ServiceImplemantion.class
package tr.kasim.Service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tr.kasim.Dao.PersonelDao;
import tr.kasim.Model.Personel;
#Service
public class PersonelServiceImpl implements PersonelService {
#Autowired
private PersonelDao personelDao;
#Override
#Transactional
public List<Personel> findAll() {
return personelDao.findAll();
}
}
Here is Dao.class
package tr.kasim.Dao;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import tr.kasim.Model.Personel;
#Repository
public interface PersonelDao extends JpaRepository<Personel, Long> {
List<Personel> findAll();
}
Lastly here is my application.properties
#MySql Connection
spring.datasource.url=jdbc:mysql://localhost:3306/exampleproject?verifyServerCertificate=false&useSSL=true
spring.datasource.username=root
spring.datasource.password=*******
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#Jpa/Hibernate
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
#Logging
logging.file=staffTracking.log
logging.level.org.springframework.web=debug
Im not sure about componentScan. When I read answers I discovered someone mentioned about it but I tried and I got still nothing. Please show me where I failed. Best Regards.
I updated Application.class, now I can deploying project but rest service not working still.
How did you try ComponentScan? The issue here seems that you have a package structure like this:
tr.kasim.Application
- Application.java
tr.kasim.Service
- PersonelService.java
- PersonelServiceImpl.java
tr.kasim.Dao
- PersonelDao.java
Now since, the mainClass is in tr.kasim.Application it would scan for bean definitions inside that package (or a sub-package in tr.kasim.Application). So,
either you move the mainClass out to a parent-package like tr.kasim, or
use #ComponentScan({ "tr.kasim.Dao", "tr.kasim.Service", "tr.kasim.Application" }) and so on.
-- Update --
Based on the discussion so far, I'd suggest taking the first option as that reduces the effort to manually enable scan for entity, repository, etc.

What is the framework class in Spring that distinguishes functionality of #Controller, #Service, #Repository

I want to understand which class in Spring framework distinguishes functionality of #Controller, #Service, #Repository annotations. Upon comparing source code of these three annotations understood that only class name is different.
Say, how does spring understand StudentController is only Controller and not Service or Repository?
#Controller
public class StudentController {
}
#Service
public class StudentService {
}
#Repository
public class StudentRepository {
}
Source codes of spring stereotype annotations
Controller.class
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface Controller {
#AliasFor(
annotation = Component.class
)
String value() default "";
}
Service.class
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface Service {
#AliasFor(
annotation = Component.class
)
String value() default "";
}
Repository.class
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface Repository {
#AliasFor(
annotation = Component.class
)
String value() default "";
}
Since source code is same for these annotations, their functionality is distinguished (as each one has different use cases) in framework classes somewhere otherwise framework allows users to use these annotations interchangeable.
I want to understand which class in Spring framework distinguishes
functionality of #Controller, #Service, #Repository annotations. Upon
comparing source code of these three annotations understood that only
class name is different.
The usage is nuanced and often your answers are going to be found by searching for references (e.g. in Eclipse.
For example, #Controller is referenced specifically in RequestMappingHandlerMapping.
Say, how does spring understand StudentController is only Controller
and not Service or Repository?
The plumbing knows what to do with specific annotations. To answer your question directly: it knows StudentController is an #Controller because you have annotated it thus. It is not annotated as #Repository, so it's not a repository.
#Controller itself has a RetentionType.RUNTIME so that Spring can inspect / check for it using reflection.
Finally, note that #Controller (and the other stereotypes you mentioned) are themselves #Components. So a type marked as #Controller is implicitly also a #Component.

Not finding repository class in spring integration test

The methods : findAll(),save(O o), findOne(long id) of interface
Repository is not found in my spring jpa integration test.
package source;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import category.IntegrationTest;
import domain.BankAccount;
import presentation.MessageContext;
import repository.BankAccountRepository;
#RunWith(SpringRunner.class)
#Category(IntegrationTest.class)
#DataJpaTest
public class BankAccountTest {
#Autowired
private BankAccountRepository repository;
#Test
public void should_find_no_customers_if_repository_is_empty() {
Iterable<BankAccount> accounts = repository.findAll();
assertNull(accounts);
}
#Test
public void shuldCreateBankAccount() {
BankAccount accounts = new BankAccount(100);
repository.save(accounts);
BankAccount accountr = repository.findOne(1l);
assertNotNull(accountr);
}
}
The repository interface looks like this
package repository;
import org.springframework.data.repository.Repository;
import domain.BankAccount;
public interface BankAccountRepository extends Repository<BankAccount, Long> {}
I have also implemeneted a configuration file
package repository;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#Configuration
#EnableJpaRepositories
public class PersistentContext {}
the classes is placed like this
Component structure
What must i to compile the code without errors?
interface Repository is empty interface ,it's common interface for spring data repositories . There is no any method , see Repository API .
If you need method findAll(),save(O o), findOne(long id) you need use CrudRepository - it's sub interface for interface Repository , or you can use JpaRepository - it's extension of CrudRepository.

Getting a reference to a Jersey REST resource method from the URL

I'm doing some performance testing, and I want to be able to call a resource method without going through the network. I already have a framework for generating URLs, and I'd like to be able to reuse it.
For example, given the URL: www.example.com:8080/resource/method, I want to get a reference to the resource method that it calls, so that I can run it without making a network-level HTTP request. I.e., in the example below, I want to use the URL "www.frimastudio.com:8080/time" to get a reference to the method getServerTime() that I can then call directly.
Does Jersey (or something else?) provide a way to do this, or do I have to import the specific Resource class I want to call, instantiate it, etc.? Thanks in advance!
Yes jersey is RESTful API that allow routes configuration (only with annotations)
Example :
package com.frimastudio.webservice.controller.route;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.joda.time.DateTime;
import com.frimastudio.webservice.controller.representation.Time;
#Path("/time")
#Produces(MediaType.APPLICATION_JSON)
public class TimeResource
{
public TimeResource()
{
}
#GET
public Time getServerDate()
{
return new Time(new DateTime());
}
}
with Time being a Jackson representation :
package com.frimastudio.webservice.controller.representation;
import org.hibernate.validator.constraints.NotEmpty;
import org.joda.time.DateTime;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Time
{
#NotEmpty
#JsonProperty
private String date;
public Time()
{
// Jackson deserialization
}
public Time(String date)
{
super();
this.date = date;
}
public Time(DateTime date)
{
super();
this.date = date.toString();
}
}
This doesn't seem to be possible, based on looking at the Jersey code. The lookup is performed by HttpMethodRule.Matcher, which is a private class used only to implement HttpMethodRule.accept.
Seems to me everything in accept up to if (s == MatchStatus.MATCH) { could be pulled into its own method and exposed to the user.