Java 8 - Get content of predicate (Reflection API?) - java

I use a custom access layer (not relational, not standardized in any way) which is in the form of a jar file, like an API. This access layer provides a custom way to filter the results when I ask a
"query". I wrap this custom data access layer using the Repository design pattern, following a design similar to the one described here, in order to hide its complexity to the above layers.
Therefore, one of my repository's functions to execute queries would be something like the one following:
public class Repository {
// Other methods...
public Set<CustomEntity> get(Predicate<CustomEntity> predicate) {
// code using the predicate in order to create a custom filter string
String filterExpression = ...;
Set<CustomEntity> queryResults = CustomDataAccessLayer.query(filterExpression);
return queryResults;
}
// Other methods...
}
A typical call of the above method would be something like
Set<CustomEntity> queryResults = customEntitiesRepository.get(
p -> p.property1 == "criterio 1" && p.property2 == "criterio 2"
);
Obviously, the method get would translate the predicate with two criteria in the custom access layer's filtering mechanism. However, I don't know how to retrieve the content of the predicate in order to apply the filters to the custom access layer. Is there such a mechanism? Is it feasible to use reflection API or something like that in order to retrieve a predicate's conditions?
Edit: I could retrieve all the entities from the custom access layer API and then check if they validate the predicate criteria through the Predicate.test
method. However, this would require retrieving all data
from the custom access layer in prior (eager loading), which is exactly what I am trying to avoid. I am trying to convert the predicate into a custom access layer filter string (namely the string variable filterExpression) in order to build a "lazy loading" repository.

Related

How to obtain list of count() results using JpaRepository #Query?

I'm building REST API connected to ORACLE 11G DB. API sends data to Android client using JSON. To get data I'm using JpaRepository, and #Query annotations.
I want to provide data for charts: number of contracts in years.
I have native SQL query:
select aa.ROK, count(aa.NUMER_UMOWY)
from (select distinct NUMER_UMOWY, ROK from AGR_EFEKTY) aa
group by aa.ROK order by aa.ROK
Result of query using SQL Developer look like this:
I tried to get result using native query:
But result is always like this:
or error depending what I try.
Is it possible to obtain list of count() results using #Query?
If not, what should I use?
Thanks in advance :-)
I think What you are trying to use here is spring data projection.
As mentioned in the reference doc:
Spring Data query methods usually return one or multiple instances of
the aggregate root managed by the repository. However, it might
sometimes be desirable to create projections based on certain
attributes of those types. Spring Data allows modeling dedicated
return types, to more selectively retrieve partial views of the
managed aggregates.
and particularly closed projection where all accessor methods match the target attributes. In your case the count is not an attribute of your aggregate.
To perform what you want you can use constructor as follow :
class ContractsDto{
private String rok;
private int count;
public ContractsDto(String rok, int count) {
this.rok=rok;
this.count =count;
}
// getters
}
The query will be:
#Query(value = "select new ContractsDto(aa.rok , /*count */) from fromClause")
List<ContractsDto> getContractsPerYear();

How to call multiple APIs returning Observable<Response> and aggregate their responses to a single Object

I have to create an aggregated POJO named say Product.java, by calling multiple sources/Rest APIs (#sources can be any number) and parse their individual responses (Observable<Response>) to populate relevant fields in Product.java
Observable.zip() kinda suits my requirement, but it takes a fixed no. of args, whereas in my case #sources (args) can be any configurable number.
Is there a generic/ cleaner way to do this?
List<Source> sources = //Some configuration, where sources.size()
// Call all source REST APIs in parallel where each returns an Observable<Response>
// Parse each Observable<Response> & populate the relevant fields in a shared Product.java Object. (No two responses will try to populate the same field in Product)
If the order is not important, just .merge() and .scan(); if it is important, use .concat() instead of .merge()
final Observable<MyContainer> myContainer = Observable
.merge(sources)
.scan(new MyContainer(), (myContainer, newProduct) -> {
// add newProduct to myContainer
return myContainer;
})

How to specify spring data jpa request to load collection of entity properties?

I use spring data JPA. I need in my repository request to load only collection of concrete properties colors:
#Query(value = "SELECT cd.color FROM CalendarDetails cd where cd.userCalendar.userId = :userId")
List<String> findCalendarColorsByUserWithDuplicates(#Param("userId") Long userId);
Provided solution works correctly.
I want simplify it using spring approach to load collection of the repository objects I'd use (repository public interface CalendarDetailsRepository extends JpaRepository<CalendarDetails, Long>):
List<CalendarDetails> findByUserCalendarUserId(#Param("userId") Long userId);
But I need collection of colors! Trying
List<String> findColorByUserCalendarUserId(Long userId);
I get collection of CalendarDetails
Is it possible to improve my last request following spring data approaches to load list of colors?
You can try special Projection mechanisms that Spring Data provides. It will allow you not only to optimize your queries but also to make it with pure java without using #Query.
There are a lot of ways to
make it, but I would recommend the following.
You add an interface that contains getters for the properties that you need to take from entity:
public interface ColorOnly {
String getColor();
}
Then you return the list of this interface' objects:
List<ColorOnly> findColorByUserCalendarUserId(Long userId);
To use the colours from the interface, you just invoke getColor method. You may consider simplifying it with Java 8 streams and map conversions. BTW, this one will only query colour. No other fields will be included into the query Hibernate produces.
Try to add All
findAllByUserCalendarUserId(Long userId);
BTW, IntelliJ IDEA provide very deep support of JPA repositories, so it's prevent a lot of possible issues when you create queries like this one

Spring data neo4j 4: RelationshipOperationsRepository

In older versions SDN we had following interface for repositories
org.springframework.data.neo4j.repository.RelationshipOperationsRepository;
public interface UserRelationRepository extends GraphRepository<UserEntity>, RelationshipOperationsRepository<UserEntity> {
MakeFriend rel = userRepository.getRelationshipBetween(startUser, endUser, MakeFriend.class, RelTypes.FRIEND.name());
if (rel != null) {
startUser.getFirstname() + " + " + endUser.getFirstname());
}
userRepository.createRelationshipBetween(startUser, endUser, MakeFriend.class, RelTypes.FRIEND.name());
userRepository.createRelationshipBetween(endUser, startUser, MakeFriend.class, RelTypes.FRIEND.name());
But current version does not support it. Which is the best way implement functionality like createRelationshipBetween or getRelationshipBetween in SDN?
SDN 4 does not support managing low-level graph operations using APIs.
Instead the graph operations to be performed are inferred from your domain model classes and what you do with them.
For example, create a User class as follows:
class User {
List<User> friends = new ArrayList();
}
If you now adding or remove Users in the friends list and save the User in the normal way via the standard Repository methods, this will achieve what you need automatically - the appropriate relationships will be added/removed. You don't have to tell SDN what to do because the point of an ORM/OGM is to hide you from the underlying data model and its implementation details and allow you to manipulate the domain model itself.
If you really need to perform these low-level operations directly on the graph, you use Cypher with a query method.
You can find out more about SDN 4.1 here

Is it possible to write web-service that returns a collection of generic type? Spring 3

In my db I have a number of entity classes and I run standart CRUD operations on them via Hibernate. Its not a problem to create generic dao class to make all main operations with classes. For example, in dao I have methods which look like this:
<T> List<T> loadAll(Class clazz)
Now I want to expose these methods to web-service client via Spring 3 operated web-service.
The only way I see is to implement web-methods for all entities i.e. write a class that looks like...
class BookResponse { List<BookEntity> books; }
... and return this in corresponding web-method "BookResponse getAllBooks()". This will ruin my attemts to make a code simplier by using dao with generics.
Is there are any other ways?
How can I do this without implementing web-methods for ALL my entities?
If generic web-service is not possible may be there are some other ways to resolve this task in a simple way?
UPDATE:
At the moment I am trying to implement a response class which should look like
public class ServiceResponse<T>{
#XmlElementWrapper( name = "data" )
#XmlElements( #XmlElement(name = "a", type = EntityA.class), #XmlElement(name = "b", type = EntityB.class) )
private List<T> data = new ArrayList<T>( );
//getters,setters
}
So I want to be able to insert a list of any entities mapped with annotations to this response. This produces no erros, but the response given me by web-service is empty.
I think you'll need a new POJO "GenericEntity" which can hold the information of any domain entity class instance.
It would hold a type string and an arbitrary/generic list of named attributes.
It can then be used to represent any of your real domain entities
e.g.
type = Book
attributes = (title=Order of the Phoenix, author=J K Rowling)
e.g.
type = Car
attributes = (make=Renault, model=Clio)
These examples show String attributes so you'll have to sort out if this is good enough or if you need strong typing - it's possible but harder.
You can then expose your "GenericEntity" via web services, allowing clients to make calls in and specify which domain entity they wish to search for, and even allow them to specify search criteria too.
Adds and deletes could be done in a similar way.
HTH,
David

Categories

Resources