I am using REST Data with Panache for JAX RESTful Web Service generation by extending PanacheEntityResource. In Spring land there is query builder mechanism that allows the Spring Data repository to generate an SQL query based on the name and return type of the custom method signature.
I'm trying to achieve the same thing using Panache, so far unsuccessfully.
#ResourceProperties(path = "tasks", paged = false)
public interface TaskResource extends PanacheEntityResource<Task, UUID> {
List<Task> findByOrganizationId(#QueryParam("organizationId") UUID organizationId);
}
I want to pass the organazation ID as a query parameter, such that my request will be http://localhost:8080/tasks?organizationId=1e7e669d-2935-4d6f-8b23-7a2497b0f5b0, and my response will return a list of Tasks whose organization ID matches the one provided. Is there support for this functionality?
That functionality is currently not supported.
See https://quarkus.io/guides/rest-data-panache and https://quarkus.io/guides/spring-data-rest for more details
Related
I am trying to use the #Param annotation for a custom query I built using Spring Data JPA's Query Creation such that when I pass the query parameter ?organizationId=2, only Tasks will be returned that have an organization ID that match the given param.
#RepositoryRestResource(collectionResourceRel = "tasks", path = "tasks")
public interface TaskRepository extends JpaRepository<Task, Long> {
List<Task> findByOrganizationId(#Param("organizationId") Long organizationId);
}
The problem is that when I visit the the #RepositoryRestResource path at /tasks?organizationId=2, it seems to be calling the default List<Task> findAll(); method exposed at /tasks, and all Tasks are returned.
How can I make Spring direct the request to my custom method?
All query method resources are exposed under the search resource. (See here for further information.)
http://localhost:8080/tasks/search/ should give you the list of available search endpoints. One should be : http://localhost:8080/tasks/search/findByOrganizationId, to which you can apply your parameterized search.
We have a service that simply returns the json document on a GET request. Since we do not have the POJO for the response "model", it appears we won't be able to use the auto response fields generation "goodness".
One option for us is to create the Pojos (quite large, about 50 attributes) and a corresponding controller that uses the pojos. This is awkward as we now have to maintain the model and corresponding controller just so we can auto generate the model.
Any ideas on how we can still leverage some auto generation of the response fields would be greatly appreciated.
Here's the controller I'm referring to:
#RestController
#RequestMapping("/api")
public class ProductController {
#Autowired
ProductService productService;
#RequestMapping(value = { "/products/{ids}" }, method = { RequestMethod.GET },
produces = "application/json", headers={"accept=application/json"})
#Timed
#ExceptionMetered
#LogExecutionTime
public String getProductDetails(#PathVariable("id") String id) {
return productService.getProductDetails(id);
}
At the moment I see no way of leveraging the auto generation without putting additional effort into it. Spring Auto REST Docs works by inspecting POJOs with a Jackson visitor (static introspection without runtime information) and there is currently no way of deriving the JSON fields from a string (would be dynamic at runtime). Thus, I only see two options:
The approach that you already described: Creating the corresponding POJO and using it.
Using Spring REST Docs for the corresponding test and manually document each field in the test. Might be the better option here if you do not want to alter the production code.
I have a Spring boot application using an AWS DynamoDb table which contains a list of items as such:
#DynamoDBTable(tableName = MemberDbo.TABLENAME)
public class MemberDbo {
public static final String TABLENAME = "Member";
#NonNull
#DynamoDBHashKey
#DynamoDBAutoGeneratedKey
protected String id;
// some more parameters
#DynamoDBAttribute
private List<String> membergroupIds;
}
I would like to find all members belonging to one specific groupId. In best case I would like to use CrudRepository like this:
#EnableScan
public interface MemberRepository extends CrudRepository<MemberDbo, String> {
List<MemberDbo> findByMembergroupIdsContaining(String membergroupIds); // actually I want to filter by ONE groupId
}
Unfortunately the query above is not working (java.lang.String cannot be cast to java.util.List)
Any suggestions how to build a correct query with CrudRepository?
Any suggestions how to create a query with Amazon SDK or some other Springboot-compliant methods?
Alternatively can I create a dynamoDb index somehow and filter by that index?
Or do I need to create and maintain a new table programmatically containing the mapping between membergroupIds and members (which results in a lot of overhead in code and costs)?
A solution for CrudRepository is preferred since I may use Paging in future versions and CrudRepository easily supports paging.
If I have understood correctly this looks very easy. You using DynamoDBMapper for model persistence.
You have a member object, which contains a list of membergroupids, and all you want to do is retrieve this from the database. If so, using DynamoDBMapper you would do something like this:
AmazonDynamoDB dynamoDBClient = new AmazonDynamoDBClient();
DynamoDBMapper mapper = new DynamoDBMapper(dynamoDBClient);
MemberDbo member = mapper.load(MemberDbo.class, hashKey, rangeKey);
member.getMembergroupIds();
Where you need to replace hashKey and rangeKey. You can omit rangeKey if you don't have one.
DynamoDBMapper also supports paging out of the box.
DynamoDBMapper is an excellent model persistence tool, it has strong features, its simple to use and because its written by AWS, it has seamless integration with DynamoDB. Its creators have also clearly been influenced by spring. In short, I would use DynamoDBMapper for model persistence and Spring Boot for model-controller stuff.
I'm going to implement multi-tenancy support in my Spring OAuth 2 + Spring Data Neo4j project.
I have configure my OAuth2 Authorization Server with a few different clients with a different clientId.
Also, I have added a base TenantEntity to my Spring Data Neo4j models:
#NodeEntity
public abstract class TenantEntity extends BaseEntity {
private String tenantId;
public String getTenantId() {
return tenantId;
}
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
}
All of my existing Spring Data Neo4j entities must now extend this TenantEntity.
Right now I'm going to rewrite all of my Neo4j queries in order to support this tenantId parameter.
For example current query:
MATCH (d:Decision)<-[:DEFINED_BY]-(c:Criterion) WHERE id(d) = {decisionId} AND NOT (c)<-[:CONTAINS]-(:CriterionGroup) RETURN c
I going to rewrite to following:
MATCH (d:Decision)<-[:DEFINED_BY]-(c:Criterion) WHERE id(d) = {decisionId} AND d.tenantId = {tenantId} AND c.tenantId = {tenantId} AND NOT (c)<-[:CONTAINS]-(:CriterionGroup) RETURN c
In turn for tenantId I'm going to use OAuth2 clientId and store it together with every Neo4j entity.
Is it a correct approach in order to implement multi-tenancy or Spring OAuth2/Data Neo4j can propose something more standard for this purpose out of the box ?
Since Neo4j currently has no feature to support multi-tenancy, if you particularly need this, it must be worked-around as you have done. You solution looks reasonable.
Alternatively, licensing is by machine, so it is possible to use, for example, Docker and spin up multiple Neo4j instances each on a different port.
In Spring Security, #PreFilter and #PostFilter can be used to trim/prune the argument/return object and filterObject references each element in the object and is used to loop through the argument/return Collection/Array.
However, I need to get a handle to the actual Collection/Array as a whole and not specific elements in the context. Is there any way to do this?
The reason is that I am creating an externalized authorization service that is used by Spring Security to query and prune the collection/array and this service supports querying for multiple answers in a single question. Once I get a reference to the object as a whole, I can iterate though the elements myself to create this request to the externalized service.
Can this be done in Spring Security? I am implementing this as an custom express handler.
Assuming the return value is modifiable, you can use #PostAuthorize. For example:
#PostAuthorize("#mySecurityFilter.filter(authentication, returnObject)")
List<String> findAllMessages();
This assumes you created a Bean by the name of "mySecurityFilter" that looks something like this:
#Component
public class MySecurityFilter {
public boolean filter(Authentication authentication, List<String> domain) {
// submit to service and get back all allowed values
List<String> allowed = Arrays.asList("Hello");
Iterator<String> iValues = domain.iterator();
while(iValues.hasNext()) {
String value = iValues.next();
if(!allowed.contains(value)) {
iValues.remove();
}
}
return true;
}
}