Good Morning,
I set up a local Neo4j database and want to model a graph of maven dependencies.
When I execute the following statement via the webconsole, everything works fine:
start root = node(1)
create unique root -[:ROOT]-> (n{groupId:'fancyStuff',artifactId:'somewhat', version:'1.4'})
return n
(note: rootnode is there for debugging purposes, will be replaced by actual structure later)
So, here everything works fine, no matter of how much whitespaces I take or replacing ' with "
In my java application i have the following function:
private static URI getOrCreate(Artifact artifact){
String cypherUri = SERVER_ROOT_URI + "cypher";
String cypherStatement="{\"query\" : \"start x = node(1) " +
"create unique x -[:ROOT]-> (artifact{groupId:\"" + artifact.getGroupID() +
"\", artifactId:\"" + artifact.getArtifactID() +
"\", version: \"" + artifact.getVersion() +
"\"}) return artifact ,\"params\" : {}}";
WebResource resource = Client.create()
.resource( cypherUri );
ClientResponse response = resource.accept( MediaType.APPLICATION_JSON_TYPE )
.type( MediaType.APPLICATION_JSON_TYPE )
.entity( cypherStatement )
.post( ClientResponse.class );
System.out.println( String.format( "POST to [%s], status code [%d]",
cypherUri, response.getStatus() ) );
response.close();
return response.getLocation();
}
so basically I post a json file looking like
{"query" : "start root = node(1) create unique root-[:ROOT]->(artifact{groupId:'{"query" : "start root = node(1) create unique root-[:ROOT]->(artifact{groupId:'lol',artifactId:'somewhat',version:'1.4'}) return artifact","params" : {}}
also no matter what whitespacing or "/' I use I get an http 500 error, saying the first - of the relationship -[:ROOT]-> is invalid.
Posting new nodes directly via
final String nodeEntryPointUri = SERVER_ROOT_URI + "node";
WebResource resource = Client.create().resource( nodeEntryPointUri );
ClientResponse response = resource.accept( MediaType.APPLICATION_JSON_TYPE )
.type( MediaType.APPLICATION_JSON_TYPE )
.entity( /*some json*/)
.post(ClientResponse.class);
(Disclaimer: I will move the params to the right place asap this version works ;) )
I could bet it's some totally trivial error, but I'm staring at this for over half a workday right now and none of my variations want to work.
Would be awesome if somebody knows an answer.
Greetings,
Florian Rohm
The problem is you have invalid JSON. You repeat query twice. If you delete the part between stars, does it work?
**{"query" :
"start root = node(1)
create unique root-[:ROOT]->(artifact{groupId:'**
{"query" : "start root = node(1)
create unique root-[:ROOT]->(artifact{groupId:'lol',artifactId:'somewhat',version:'1.4'})
return artifact",
"params" : {}
}
Ok, i don't know what's different with this statement but this works (I tried the param split in the above code, too):
String cypherUri = SERVER_ROOT_URI + "cypher";
JSONObject jObject = new JSONObject();
try {
Map<String, String> params = new HashMap<String, String>();
params.put("groupId", artifact.getGroupID());
params.put("artifactId", artifact.getArtifactID());
params.put("version", artifact.getVersion());
String query = "start x = node(1) create unique x-[:ROOT]->(n{groupId:{groupId},artifactId:{artifactId},version:{version} }) return n";
jObject.put("query", query);
jObject.put("params", params);
} catch (Exception e) {
e.printStackTrace();
}
WebResource resource = Client.create()
.resource( cypherUri );
ClientResponse response = resource.accept( MediaType.APPLICATION_JSON_TYPE )
.type(MediaType.APPLICATION_JSON_TYPE)
.entity(jObject.toString())
.post(ClientResponse.class);
But anyways, the second attempt is nicer and I won't complain :D
It just bugs me not to know what's going on there...
Related
I am using angular1 with java, spring-mvc framework. And from frontend service/controller , I need to pass 2 different types of object to the java-backend-controller. For example, say my 2 objects are:
self.basicBean = {id: null, name: self.fileInfo.fileLocation};
self.delimiterToChk = {name:'', value:self.delimiter}
My current javascript controller which is seeing error at this point is :
return $http.post( 'submenu/layout/guess/' + clientId + '/' + maxColumns + "/" + origin ,
delimiterObj,
folderPathBean)
.then(
function( response )
{
return response.data;
},
function( errResponse )
{
console.error( 'Error while guessFieldLayout' );
return $q.reject( errResponse );
}
);
My backend java-controller looks like :
#RequestMapping( value = "/layout/guess/{clientId}/{maxColumns}/{origin}", method = RequestMethod.POST )
public ResponseEntity<?> guessFieldLayout( #PathVariable( "clientId" ) long clientId,
#PathVariable( "maxColumns" ) int maxColumns,
#RequestBody Delimiter delimiterObj,
#PathVariable( "origin" ) String origin,
#RequestBody BasicBean basicBeanFolderPath )
{
try{}
}
I am seeing 400 error and guessing it is because I am not suppose to send the objects as 2 Request body. However, how to put it in one request body and how to map that at java controller end? Any example available?
I've to transfer data from one machine to another machine connected on a network. May be some 10-20 values to be transfered and that depends. All I do is pack up/ marshal the values in a json and transfer it to another server (say which is another machine connected on a network) via a http post call. Say the data flows from ServerA to ServerB in ServerA I have to pack up all the data to construct the json and in the ServerB I have to unmarshal it which eats up most of my code like the following
String student_id = json.getString("sid");
String student_role_number = json.getString("rnumber");
String student_name = json.getString("name");
String isDayScholar = json.optString("dayscholar", "false");
String stream = json.optString("stream", "");
String class_section = json.getString("section");
It's light when the value is 4-5 when there are more number of values like 20-25 I feel quite heavy in doing this get/set operations.Is there any better way to avoid/minimise this?
It's light when the value is 4-5 when there are more number of values like 20-25, If you could just hardcode all the required keys in some data structure then that might help. For example in your case all the necessary keys are sid,rnumber,name,dayscholar etc.
Keep a separate hardcoded data struct for your keys
org.json.JSONObject jsonObject = new org.json.JSONObject();
java.util.Map<String , Object> otherMap = new java.util.HashMap<>();
String[] myLovedKeys = {"sid" , "rnumber" , "name" , "dayscholar" , "stream" , "section"};
for( int x = 0; x < myLovedKeys.length; x++ )
{
if( myLovedKeys[x].equals("dayscholar") || myLovedKeys[x].equals("stream") )
{
String value = "";
if( myLovedKeys[x].equals("dayscholar") )
{
value = json.optString( myLovedKeys[x] , "false" );
jsonObject.put( myLovedKeys[x] , value );
otherMap.put( myLovedKeys[x] , value );
}
else
{
value = json.optString( myLovedKeys[x] , "" ); // stream key-value
jsonObject.put( myLovedKeys[x] , value );
otherMap.put( myLovedKeys[x] , value );
}
}
else
{
String keyValue = json.getString( myLovedKeys[x] );
jsonObject.put( myLovedKeys[x] , keyValue );
otherMap.put( myLovedKeys[x] , keyValue );
}
}
This will allow you to exactly know which key is currently being processed inside the loop and you can handle diverse behaviors depending on which key you are interested in dealing with
Now the reason why I have declared a JSONObject and a java.util.Map is because I simply want to elaborate the fact that if you are missing org.json.* library, then you can easily get away by using a java.util.Map, but if you have the org.json* library, then you can also deal with problem in a more comfortable manner. Now lets say we wanted to access the data then we could easily try things like
for( int x = 0; x < myLovedKeys.length; x++ )
{
System.out.println( "java.util.Map: [" myLovedKeys[x] + "=" + otherMap.get( myLovedKeys[x] ) );
System.out.println( "org.json.JSONObject: " + myLovedKeys[x] + "=" + jsobObject.getJSONObject( myLovedKeys[x] ) );
}
In a similar fashion, you can modify and update those values
otherMap.put( myLovedKeys[0] , "SomeValue");
otherMap.put( myLovedKeys[1] , "Other Value" );
otherMap.put( "sid" , "SomeValue" );
otherMap.put( "rnumber" , "toSomeName");
//myLovedKeys[0] = "sid" , myLovedKeys[1] = "rnumber"
Similarly you can have the some changes reflected in the jsonObject variable. What you have to realize is that you have to deal with the pain of hardcoding all the key-names somewhere in your code, and yes that is going to take some typing :), Please let me know if that is still not enough to help your case
I am using the Java Bolt driver (1.0.1) and I am wondering there is a way to convert the result to Json (possibly the same as in the REST api)?
I tried to use gson in this way:
Result r = null;
try ( Transaction tx = graphDb.beginTx() )
{
r = graphDb.execute("MATCH...");
tx.success();
} catch {...}
new Gson().toJson(result);
but what I get is:
java.lang.StackOverflowError
at com.google.gson.internal.$Gson$Types.canonicalize($Gson$Types.java:98)
at com.google.gson.reflect.TypeToken.<init>(TypeToken.java:72)
etc...
The API you show is not the Bolt-Driver, it's the embedded Java-API.
In the bolt-driver you can do
Driver driver = GraphDatabase.driver( "bolt://localhost", AuthTokens.basic( "neo4j", "neo4j" ) );
Session session = driver.session();
StatementResult result = session.run( "MATCH (a:Person) WHERE a.name = 'Arthur' RETURN a.name AS name, a.title AS title" );
while ( result.hasNext() ) {
Record record = result.next();
gson.toJson(record.asMap());
}
session.close();
driver.close();
I am developing an app in flask and need to do the same and then get it into a response but in Python. Im using jsonify instead of gson. Any suggestions??? Code right here:
#concepts_api.route('/concepts', methods=['GET'])
def get_concepts_of_conceptgroup():
try:
_json = request.json
_group_name = _json['group_name']
if _group_name and request.method == 'GET':
rows = concepts_service.get_concepts_of_conceptgroup(_group_name)
resp = jsonify(rows)
resp.status_code = 200
return resp
return not_found()
except:
message = {
'status': 500,
'message': 'Error: Imposible to get concepts of conceptgroup.',
}
resp = jsonify(message)
resp.status_code = 500
return resp
excluse if this is a duplicate, although I did not find the answer so far.
I have an application that creates nodes and relationships via cypher statement against the REST-API. I create relationships with the below code:
public URI createRelationship(GraphNodeTypes sourceType, URI sourceNode,
GraphNodeTypes targetType, URI targetNode,
GraphRelationshipTypes relationshipType, String[] jsonAttributes) {
URI relationShipLocation = null;
String cypherArt = getNodeIdFromLocation(sourceNode)+"-[:"+relationshipType+"]->"+getNodeIdFromLocation(targetNode);
logger.info("creating relationship ({}:{}) -[:{}]-> ({}:{})",
sourceType,
getNodeIdFromLocation(sourceNode),
relationshipType,
targetType,
getNodeIdFromLocation(targetNode));
try {
URI finalUrl = new URI( sourceNode.toString() + "/relationships" );
String cypherStatement = generateJsonRelationship( targetNode,
relationshipType,
jsonAttributes );
logger.trace("sending CREATE RELATIONSHIP cypher as {} to endpoint {}", cypherStatement, finalUrl);
WebResource resource = Client.create().resource( finalUrl );
ClientResponse response = resource
.accept( MediaType.APPLICATION_JSON )
.type( MediaType.APPLICATION_JSON )
.entity( cypherStatement )
.post( ClientResponse.class );
String responseEntity = response.getEntity(String.class).toString();
int responseStatus = response.getStatus();
logger.trace("POST to {} returned status code {}, returned data: {}",
finalUrl, responseStatus,
responseEntity);
// first check if the http code was ok
HttpStatusCodes httpStatusCodes = HttpStatusCodes.getHttpStatusCode(responseStatus);
if (!httpStatusCodes.isOk()){
if (httpStatusCodes == HttpStatusCodes.FORBIDDEN){
logger.error(HttpErrorMessages.getHttpErrorText(httpStatusCodes.getErrorCode()));
} else {
logger.error("Error {} sending data to {}: {} ", response.getStatus(), finalUrl, HttpErrorMessages.getHttpErrorText(httpStatusCodes.getErrorCode()));
}
} else {
JSONParser reponseParser = new JSONParser();
Object responseObj = reponseParser.parse(responseEntity);
JSONObject jsonResponseObj = responseObj instanceof JSONObject ?(JSONObject) responseObj : null;
if(jsonResponseObj == null)
throw new ParseException(0, "returned json object is null");
//logger.trace("returned response object is {}", jsonResponseObj.toString());
try {
relationShipLocation = new URI((String)((JSONObject)((JSONArray)((JSONObject)((JSONArray)((JSONObject)((JSONArray)jsonResponseObj.get("results")).get(0)).get("data")).get(0)).get("rest")).get(0)).get("self"));
} catch (Exception e) {
logger.warn("CREATE RELATIONSHIP statement did not return a self object, returning null -- error was {}", e.getMessage());
relationShipLocation = null;
}
}
} catch (Exception e) {
logger.error("could not create relationship ");
}
return relationShipLocation;
}
private static String generateJsonRelationship( URI endNode,
GraphRelationshipTypes relationshipType, String[] jsonAttributes ) {
StringBuilder sb = new StringBuilder();
sb.append( "{ \"to\" : \"" );
sb.append( endNode.toString() );
sb.append( "\", " );
sb.append( "\"type\" : \"" );
sb.append( relationshipType.toString() );
if ( jsonAttributes == null || jsonAttributes.length < 1 ){
sb.append( "\"" );
} else {
sb.append( "\", \"data\" : " );
for ( int i = 0; i < jsonAttributes.length; i++ ) {
sb.append( jsonAttributes[i] );
if ( i < jsonAttributes.length - 1 ){
// Miss off the final comma
sb.append( ", " );
}
}
}
sb.append( " }" );
return sb.toString();
}
My problem is that I would like to check if a given relationship of given type already exists between two nodes PRIOR creating it.
Can someone tell me, how to query for a relationship???
With nodes I do a MATCH like this:
MATCH cypher {"statements": [ {"statement": "MATCH (p:SOCIALNETWORK {sn_id: 'TW'} ) RETURN p", "resultDataContents":["REST"]} ] }
against the endpoint
http://localhost:7474/db/data/transaction/<NUMBER>
How would I construct the statement to check for a relationship, say between node 6 and 5 or whatever?
Thanks in advance,
Chris
You might want to consider doing this through cypher, and using the MERGE/ON CREATE/ON MATCH keywords.
For example, you could do something like this:
create (a:Person {name: "Bob"})-[:knows]->(b:Person {name: "Susan"});
MATCH (a:Person {name: "Bob"}), (b:Person {name: "Susan"})
MERGE (a)-[r:knows]->(b)
ON CREATE SET r.alreadyExisted=false
ON MATCH SET r.alreadyExisted=true
RETURN r.alreadyExisted;
This MATCH/MERGE query that I provide here will return true or false, depending on whether the relationship already existed or not.
Also, FWIW it looks like the code you're using to accumulate JSON via StringBuilder objects is likely to be ponderous and error prone. There are plenty of good libraries like Google GSON that will do JSON for you, so you can create JSON objects, arrays, primitives, and so on -- then let the library worry about serializing it properly to a string . This tends to make your code a lot cleaner, easier to maintain, and when you mess something up about your JSON formatting (we all do), it's way easier to find than when you accumulate strings like that.
In Java
Relationship getRelationshipBetween(Node n1, Node n2) { // RelationshipType type, Direction direction
for (Relationship rel : n1.getRelationships()) { // n1.getRelationships(type,direction)
if (rel.getOtherNode(n1).equals(n2)) return rel;
}
return null;
}
I have some issue with the code below, req.getHeader() is returning NULL
// The code below returns the expected value
String header = req.getHeader("x-key");
String size = req.getHeader("x-size");
String contentType = req.getContentType();
logger.info("Content-Length: " + req.getContentLength());
logger.info("x-key : " + header);
logger.info("x-size : " + size);
// The value of req.getHeader below is returning NULL
for (Enumeration e = req.getHeaderNames(); e.hasMoreElements();) {
String headerName = (String) e.nextElement();
logger.info("Name = " + headerName + " " + "Value = " + req.getHeader(headerName ));
}
What could be the problem?
Your code looks OK. If getHeader() returns null the header is indeed null, i.e. was not sent by client.
So, first check your client and be sure it sends the header. Second, try to use network sniffer, e.g. Wireshark and record the network activity.
If you need more assistance please post your client's code.
The below is part of the extract from the api docs.
public java.util.Enumeration getHeaderNames()
Some servlet containers do not allow servlets to access headers using this method, in which case this method returns null