Spring Data Neo4j custom query list params not use converter - spring-data-neo4j

NodeEntity:
#NodeEntity(label = "User")
public class UserNode {
#GraphId
private Long _gid;
#Index(unique = true, primary = true)
#Convert(ObjectIdConverter.class)
private ObjectId id;
}
Converter:
public class ObjectIdConverter implements AttributeConverter<ObjectId, String>{
#Override
public String toGraphProperty(ObjectId value) {
return ObjectIdUtils.compressed(value);
}
#Override
public ObjectId toEntityAttribute(String value) {
return ObjectIdUtils.uncompress(value);
}
}
Repository:
public interface UserNodeRepository extends GraphRepository<UserNode> {
#Query("MATCH (user:User) WHERE user.id IN {0} RETURN user")
List<UserNode> findByIdIn(List<ObjectId> ids);
}
UserNodeRepository#findByIdIn is custom query. but the request parameter directly convert to json without using ObjectIdConverter.
Log:
o.n.o.drivers.bolt.request.BoltRequest : Request: MATCH (user:User) WHERE user.id IN {0} RETURN user with params {0=[{timestamp=1500442853, machineIdentifier=11302907, processIdentifier=11906, counter=4709865, time=1500442853000, date=1500442853000, timeSecond=1500442853}, {timestamp=1500445335, machineIdentifier=11302907, processIdentifier=11906, counter=4709946, time=1500445335000, date=1500445335000, timeSecond=1500445335}, {timestamp=1500447522, machineIdentifier=11302907, processIdentifier=11906, counter=4710014, time=1500447522000, date=1500447522000, timeSecond=1500447522}, {timestamp=1500448399, machineIdentifier=11302907, processIdentifier=11906, counter=4710092, time=1500448399000, date=1500448399000, timeSecond=1500448399}]}
Is this the SDN expectation or what concepts have I lost?

This is not possible for finders with custom #Query. There is no way for OGM to know that your parameter relates to a property with #Convert annotation (the method name is not used at all). To solve this convert to your property type manually instead and use that as a parameter:
#Query("MATCH (user:User) WHERE user.id IN {0} RETURN user")
List<UserNode> findByIdIn(List<String> ids);
However this works fine for derived finders - OGM knows the field, and the #Convert annotation with the right converter, from the method name.
Example with single parameter:
List<UserNode> findById(ObjectId id);
Unfortunately there seems to be a bug for the IN operator and a collection parameter with:
// doesn't work
List<UserNode> findByIdIn(List<ObjectId> ids);
I have created a jira issue.

Related

Wso2 XACML get custom attributes

I am using Wso2 IS 5.11.0, I have a requirement where I need to fetch the user attributes by calling web-service based.
Below is the sample attribute finder code:
public class CustomPIPAttributeFinder extends AbstractPIPAttributeFinder {
private static final String PIP_NAME = "CustomPIPAttributeFinder";
private static final Set<String> SUPPORTED_ATTRIBUTES;
private static final Log log = LogFactory.getLog(CustomPIPAttributeFinder.class);
static {
SUPPORTED_ATTRIBUTES = new HashSet<String>();
SUPPORTED_ATTRIBUTES.add(CustomPIPConstants.SAMPLE_ATTRIBUTE_ID);
SUPPORTED_ATTRIBUTES.add(CustomPIPConstants.SAMPLE_ATTRIBUTE_NAME);
SUPPORTED_ATTRIBUTES.add(CustomPIPConstants.SAMPLE_CATEGORY);
}
#Override
public Set<String> getAttributeValues(URI attributeType, URI attributeId, URI category, String issuer,
EvaluationCtx evaluationCtx) throws Exception {
//code
}
private String retrieveSampleName(String accessToken) {
String sampleName = null;
// TODO: Get the value of the sample name from the sampleID from the datasource
return sampleName;
}
/**
* Since we override the {#link #getAttributeValues(URI, URI, URI, String, EvaluationCtx)} this won't be called.
*/
#Override
public Set<String> getAttributeValues(String subject, String resource, String action, String environment,
String attributeId, String issuer) throws Exception {
throw new UnsupportedOperationException("Method unsupported in the context");
}
public void init(Properties properties) throws Exception {
}
public String getModuleName() {
return PIP_NAME;
}
public Set<String> getSupportedAttributes() {
return SUPPORTED_ATTRIBUTES;
}
}
In the sample code we can fetch only one attribute per request.But how can we return multiple attributes before executing policy or get multiple attributes in one request from custom attribute finder. Is there any way to achieve this flow.
As per above code request attribute find(returns only one) in the example it will increase the overhead as for each attribute lookup we are calling web-service every time as it'll increase overhead.

Update User defined object of the dynamoDb item using UpdateItemRequest

We have a DynamoDB table Test which has an attribute Template. Bellow are the class definitions. I would like to update the Template attribute or some of its attribute based on certain condition. I tried doing the same using UpdateItemRequest but unable to find a way to update the template attribute since everything is converted to either string, number or bytes.
Code for reference.
#DynamoDbBean
public class Test implements NoSQLEntity {
private String name;
private Template template;
#DynamoDbAttribute("name")
public String getName() {
return name;
}
#DynamoDbAttribute("template")
public Template getTemplate() {
return template;
}
}
#DynamoDbBean
public class Template {
private String pk;
private String name;
private List<String> demo;
#DynamoDbAttribute("pk")
public String getPk() {
return this.pk;
}
#DynamoDbAttribute("name")
public String getName() {
return name;
}
#DynamoDbAttribute("demo")
public List<String> getdemo() {
return demo;
}
}
Sample update code:
UpdateItemRequest request = UpdateItemRequest.builder()
.tableName("Test")
.key(itemKey)
.updateExpression("SET tmpt = :tmt")
.expressionAttributeValues(expressionValues)
.build();
Here I am unable to build the :tmt using the AttributeValue. Can someone please guide me?
Here is a Readme from the Eng team that you may find useful:
https://github.com/aws/aws-sdk-java-v2/tree/master/services-custom/dynamodb-enhanced
DynamoDb Enhanced provides DefaultAttributeConverterProvider that will identify a converter that can convert the specific Java type into the AttrbuteValue type that can used to update the item.
Smaple Code:
AttributeValue value = DefaultAttributeConverterProvider.create()
.converterFor(EnhancedType.documentOf(Template.class,
TableSchema.fromBean(Template.class)))
.transformFrom(template);
Can then put this value in the expressionValues map.
Map<String, AttributeValue> expressionValues = new HashMap<>();
expressionValues.put(":tmt", value);
UpdateItemRequest request = UpdateItemRequest.builder()
.tableName("Test")
.key(itemKey)
.updateExpression("SET tmpt = :tmt")
.expressionAttributeValues(expressionValues)
.build();

Should I expect Neo4jOperations#queryForObjects to work with #QueryResult POJOs?

Neo4jOperations#queryForObjects() doesn't seem to play well with #QueryResult POJOs - it always says that result set is empty.
Trying Neo4jOperations#queryForObjects - it says result is empty:
#Test
public void thisDoesNotWork() {
Iterable<ClassNodeIdAndName> result = neo4jOperations.queryForObjects(
ClassNodeIdAndName.class,
"MATCH (c:ClassNode) RETURN ID(c) AS id, c.name AS name",
new HashMap<>());
assertTrue(result.iterator().hasNext());
}
Trying Neo4jOperations#query - says result is NOT empty:
#Test
public void thisWorksFine() {
Result result = neo4jOperations.query(
"MATCH (c:ClassNode) RETURN ID(c) AS id, c.name AS name",
new HashMap<>());
assertTrue(result.iterator().hasNext());
}
Trying repository with #Query - says result is NOT empty:
#Test
public void thisWorksFineAsWell() {
List<ClassNodeIdAndName> classNodeIdsAndNames = classNodeRepository.getAllIdsAndNames();
assertFalse(classNodeIdsAndNames.isEmpty());
}
public interface ClassNodeRepository extends GraphRepository<ClassNode> {
#Query("MATCH (c:ClassNode) RETURN ID(c) AS id, c.name AS name")
List<ClassNodeIdAndName> getAllIdsAndNames();
}
#QueryResult
public class ClassNodeIdAndName {
public Long id;
public String name;
}
Documentation says that
Iterable queryForObjects(Class entityType,
entityType - The Class denoting the type of entity to return
But I'm confused whether I should look at type of entity or at for objects. If it's not supposed to handle #QueryResult, I would expect it to throw instead of returning no results.
I'm using spring-data-neo4j 4.1.3.RELEASE
#QueryResult is a Spring Data Neo4j concept that applies only to Spring Repositorys.
Neo4jOperations is a thin wrapper around the Neo4j OGM's Session class and consequently does not handle the concept of returning query result objects.
Also see: SDN 4 Session.query doesn't work for #QueryResult

#RequestParam spring MVC , make one of two request params mandatory

I am writing a service wherein I take in either an id or a location and I want to enforce the constraint that either the id or the location must be specified in my #Controller
#Controller
public class HelloController {
#RequestMapping(value="/loc.json",method = RequestMethod.GET)
public #ResponseBody String localiaztionRequest(#RequestParam(value = "location", required = false) String callback
,#RequestParam(value = "id", required = false) String uuid
,#RequestParam(value = "callback", required = false) String callback) {
//model.addAttribute("message", "Hello world!");
return "hello";
}
For clarity, I want each request to send either the location parameter or the id parameter. How do I enforce such a constraint on a pair of input parameters? Also as an aside could someone please explain to me the use of ModelMap , what is the effect of model.addAttribute("message","Hello World!") ?
Sorry if the questions seem rather naive, I'm extremely new to the spring framework.
Thanks in advance.
I think you should split it into two different controller methods
#RequestMapping(value="/loc.json",method = RequestMethod.GET, params={"location"})
public #ResponseBody String localizationRequestByLoc(#RequestParam String location, #RequestParam String callback) {
//model.addAttribute("message", "Hello world!");
return "hello";
}
#RequestMapping(value="/loc.json",method = RequestMethod.GET, params={"id"})
public #ResponseBody String localizationRequestById(#RequestParam String id, #RequestParam String callback) {
//model.addAttribute("message", "Hello world!");
return "hello";
}
One way to accomplish this (although indirect) would be to create a new object model representing the data to be passed in and another representing the data type and requiring both elements.
public enum MethodType
{
First,
Second
}
public class Filter
{
[Required]
public MethodType {get;set;}
[Required]
public string Data {get;set;}
}
use this object for the action method and view
and let the action method in the controller convert the object

How to send a property as a string in RestEasy response?

I have a class called Product which has a property called id of type long. Below is the class
public class Product {
private long id;
}
The value of id is beyond the value which javascript can handle. I realized this after seeing the below link
Parse json in javascript - long numbers get rounded
I dont want to declare the field as String in the domain class. But I want to say to RestEasy that it has to send the value as a string in the json response.
How can I do this? I dont want to use any third party api. Is it possible in RestEasy. I have gone through the documentation but did not find any such annotation or may be I did not go through the documentation properly.
Can anyone please help. Thanks all in advance.
If you are using Jackson as JSON Serializer you can extend the JacksonJsonProvider:
#Provider
public class JsonProvider extends org.codehaus.jackson.JacksonJsonProvider {
public JsonProvider() {
ObjectMapper objectMapper = locateMapper(ObjectMapper.class, MediaType.APPLICATION_JSON_TYPE);
objectMapper.configure(org.codehaus.jackson.JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
}
}
If you are using Jettison you can register a custom XmlAdapter:
public class LongAdapter extends XmlAdapter<String, Long> {
#Override
public String marshal(Long id) throws Exception {
if (id == null) {
return "";
}
return id.toString();
}
#Override
public Long unmarshal(String id) throws Exception {
return Long.parseLong(id);
}
}