spring data neo4j rest projection returns null when using SpEL expression on nested object - spring-data-neo4j

Consider the following output is produced:
Case 1: while retrieving the nested object from neo4j using spring data neo4j interface (projection)
{
"name": "Dhoni",
"currentLocation": {
"city": {
"name": "qwerqwer",
"regionalState": {
"state": {
"name": "zxvcxzcvc"
}
}
}
}
}
Projection Interface:
public interface PersonProjection {//Root
String getName();
CurrentLocationProjection getCurrentLocation();
public interface CurrentLocationProjection { // has relationship Props
CityProjection getCity(); // target object in entity mapping
interface CityProjection {
String getName();
RegionalStateProjection getRegionalState();
interface RegionalStateProjection { // has relationship Props
StateProjection getState(); // target object in entity mapping
interface StateProjection {
String getName();
}
}
}
}
}
Case 2: When i tried to get the nested values mapped to 1st level using SpEL, works fine as u can see below
public interface PersonProjection {//Root
String getName();
CurrentLocationProjection getCurrentLocation();
public interface CurrentLocationProjection {
#Value("#{target.city.name}")
String getCityName();
#Value("#{target.city.regionalState.state.name}")
String getStateName();
}
}
gives output as:
{
"name": "Deva",
"currentLocation": {
"cityName": "qwerqwer",
"stateName": "zxvcxzcvc"
}
}
Case 3:
Issue:
However, when i try to get nested values mapped to (root level / root node) itself using SpEL via #Value as below:
public interface PersonProjection {
String getName();
#Value("#{target.currentLocation.city.name}")
String getCityName();
#Value("#{target.currentLocation.city.regionalState.name}")
String getStateName();
}
expected output:
{
"name": "Dhoni",
"cityName": "qwerqwer",
"stateName": "zxvcxzcvc"
}
But, it throws the following error stating currentLocation is null as below: (but it has value)
WARN 13600 --- [nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: EL1007E: Property or field 'city' cannot be found on null; nested exception is com.fasterxml.jackson.databind.JsonMappingException: EL1007E: Property or field 'city' cannot be found on null (through reference chain: com.sun.proxy.$Proxy162["currentLocation"])]
I'm bit confused how it works in 1st-level and not in the root level?
could someone please point my mistake / guide me to achieve the expected output. Thanks.
Note: SDN (Spring Data Neo4j) version 6.1.2 for ref.

There was a bug in Spring Data Neo4j regarding Spring Expression Language using related entities that are not part of the projection.
https://github.com/spring-projects/spring-data-neo4j/issues/2325
tl;dr;
it is solved in Spring Data Neo4j 6.1.3

Related

Google place API returns same place for two different place with same name

I am using Google place API. While it works fine there is a case where it fails. Place API returns same place for "Gorakhpur, Uttar pradesh" and "Gorakhpur, Haryana". It returns "Gorakhpur, Haryana" for both places.
autocompleteFragmentSource = (PlaceAutocompleteFragment) getFragmentManager().findFragmentById(R.id.place_autocomplete_fragment_source);
autocompleteFragmentSource.setOnPlaceSelectedListener(new PlaceSelectionListener() {
#Override
public void onPlaceSelected(Place place) {
sourceAddress = (String) place.getAddress();
}
#Override
public void onError(Status status) {
Toast.makeText(MainActivity.this, "An Error Occured!", Toast.LENGTH_SHORT).show();
}
});
Now source address is same when I select Gorakhpur, Uttar pradesh and Gorakhpur, Haryana from google place autocomplete.
Note: There is no issue with other places having similar names.

Akka.net Testkit does not mark test case failed despite ActorInitializationException exception

Following is the actor, I've defined (trying to get my head around persistent actor!!)
public class Country : ReceivePersistentActor
{
public override string PersistenceId => GetType().Name + state.Id;
private CountryState state;
public Country()
{
Command<CreateCountry>(CreateCountry);
}
private bool CreateCountry(CreateCountry cmd)
{
Persist(new CountryCeated
{
Id = cmd.Id,
Code = cmd.Code,
Description = cmd.Description,
Active = cmd.Active
}, evt =>
{
state = new CountryState
{
Id = evt.Id,
Code = evt.Code,
Description = evt.Description,
Active = evt.Active
};
});
return true;
}
}
Following is unit test case that I've defined:
[TestClass]
public class CountrySpec : TestKit
{
[TestMethod]
public void CountryActor_Should_Create_A_Country()
{
var country = Sys.ActorOf(Props.Create(() => new Country()), "Country");
country.Tell(new CreateCountry(Guid.NewGuid(), "UK", "United Kingdom", true));
ExpectNoMsg();
}
}
When I run the test case, there is an exception that I can see in the output window of the test case
[ERROR][25/08/2016 08:25:07][Thread 0007][akka://test/user/Country] Object reference not set to an instance of an object.
Cause: [akka://test/user/Country#552449332]: Akka.Actor.ActorInitializationException: Exception during creation ---> System.NullReferenceException: Object reference not set to an instance of an object.
at Domain.Country.get_PersistenceId() in Y:\Spikes\StatefulActors\Domain\Country.cs:line 9
at Akka.Persistence.Eventsourced.StartRecovery(Recovery recovery)
at Akka.Persistence.Eventsourced.AroundPreStart()
at Akka.Actor.ActorCell.<>c__DisplayClass154_0.<Create>b__0()
at Akka.Actor.ActorCell.UseThreadContext(Action action)
at Akka.Actor.ActorCell.Create(Exception failure)
--- End of inner exception stack trace ---
at Akka.Actor.ActorCell.Create(Exception failure)
at Akka.Actor.ActorCell.SysMsgInvokeAll(EarliestFirstSystemMessageList messages, Int32 currentState)
but the test case is marked as success
Is there any way/settings in the TestKit, where it can be set such that for any exception, mark the test case failed?
By default, any exceptions inside actors are encapsulated - that means they don't bubble up, blowing the rest of the system.
Actors come in systems, and can be tested by observing the way they communicate with each other. Usually it comes up to providing inputs and asserting outputs from actor system - in your case test has passed, since you haven't validated any output. From the perspective of your test, this actor could be dead and it wouldn't make a difference.
Validating an outputs (either by assertion inside actor itself or i.e. using a custom test journal) is the best way to work with tests.
If for some reason you still have to catch exceptions inside actors, you could create supervision strategy bound to i.e. TestActor, where all exceptions could be forwarded:
public class TestingStrategy : OneForOneStrategy
{
protected TestingStrategy(IActorRef probe) : base(exception =>
{
probe.Tell(exception);
return DefaultDecider.Decide(exception);
}) { }
}

Custom Data Source on Rendering Items

I'm having a Sitecore 8 MVC solution, and I have to extend the behavior of Data Source. It's pretty similar to what other people have done with queryable datasources before (such as http://www.cognifide.com/blogs/sitecore/reduce-multisite-chaos-with-sitecore-queries/ etc), but I've hooked into the <mvc.getXmlBasedLayoutDefinition> pipeline instead. It works fine and my custom data sources are resolved as they are entered in the layouts field on an item or on standard values.
But, when the custom data source is specified as a default data source on a rendering item, things becomes a bit trickier. I could solve it through the same pipeline, but that solution didn't look very nice. It means I'd have to load each rendering that hasn't a data source specified in the layout, and do the processing and resolve it from there. There must be a more natural way of doing this.
Does anyone know where to put such implementation logic for the default data source? (The <resolveRenderingDatasource> pipeline looked promising, but didn't execute in this scenario)
From what I understand, you may want to extend XmlBasedRenderingParser class. Here are the steps that should do the trick:
Create a new file App_Config\include\Sitecore.Mvc.Custom.config:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<initialize>
<processor
patch:after="processor[#type='Sitecore.Mvc.Pipelines.Loader.InitializeRoutes, Sitecore.Mvc']"
type="My.Assembly.Namespace.RegisterCustomXmlBasedRenderingParser, My.Assembly"/>
</initialize>
</pipelines>
</sitecore>
</configuration>
Create CustomXmlBasedRenderingParser class:
using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Mvc.Extensions;
using Sitecore.Mvc.Presentation;
namespace My.Assembly.Namespace
{
public class CustomXmlBasedRenderingParser : XmlBasedRenderingParser
{
protected override void AddRenderingItemProperties(Rendering rendering)
{
RenderingItem renderingItem = rendering.RenderingItem;
if (renderingItem != null && !rendering.DataSource.ContainsText())
{
rendering.DataSource = ResolveRenderingItemDataSource(renderingItem);
}
base.AddRenderingItemProperties(rendering);
}
private static string ResolveRenderingItemDataSource(RenderingItem renderingItem)
{
string dataSource = string.Empty;
if (renderingItem.DataSource != null && renderingItem.DataSource.StartsWith("query:"))
{
string query = renderingItem.DataSource.Substring("query:".Length);
Item contextItem = Context.Item;
Item queryItem = contextItem.Axes.SelectSingleItem(query);
if (queryItem != null)
{
dataSource = queryItem.Paths.FullPath;
}
}
return dataSource;
}
}
}
Create RegisterCustomXmlBasedRenderingParser class:
using Sitecore.Mvc.Configuration;
using Sitecore.Mvc.Presentation;
using Sitecore.Pipelines;
namespace My.Assembly.Namespace
{
public class RegisterCustomXmlBasedRenderingParser
{
public virtual void Process(PipelineArgs args)
{
MvcSettings.RegisterObject<XmlBasedRenderingParser>(() => new CustomXmlBasedRenderingParser());
}
}
}
What is more, if you want your code to be executed for DataSource defined on both Rendering and Presentation Details, you should be able to use the code below:
using System.Xml.Linq;
using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Mvc.Presentation;
namespace My.Assembly.Namespace
{
public class CustomXmlBasedRenderingParser : XmlBasedRenderingParser
{
public override Rendering Parse(XElement node, bool parseChildNodes)
{
Rendering rendering = base.Parse(node, parseChildNodes);
ResolveRenderingItemDataSource(rendering);
return rendering;
}
private static void ResolveRenderingItemDataSource(Rendering rendering)
{
if (rendering.DataSource != null && rendering.DataSource.StartsWith("query:"))
{
string query = rendering.DataSource.Substring("query:".Length);
Item contextItem = Context.Item;
Item queryItem = contextItem.Axes.SelectSingleItem(query);
if (queryItem != null)
{
rendering.DataSource = queryItem.Paths.FullPath;
}
}
}
}
}
Please remember that this code is not tested properly and may not work out of the box in your environment. Anyway I hope it will give you at least a good indication where to start.

Mongodb - regex match of keys for subdocuments

I have some documents saved in a collection (called urls) that look like this:
{
payload:{
url_google.com:{
url:'google.com',
text:'search'
}
}
},
{
payload:{
url_t.co:{
url:'t.co',
text:'url shortener'
}
}
},
{
payload:{
url_facebook.com:{
url:'facebook.com',
text:'social network'
}
}
}
Using the mongo CLI, is it possible to look for subdocuments of payload that match /^url_/? And, if that's possible, would it also be possible to query on the match's subdocuments (for example, make sure text exists)?
I was thinking something like this:
db.urls.find({"payload":{"$regex":/^url_/}}).count();
But that's returning 0 results.
Any help or suggestions would be great.
Thanks,
Matt
It's not possible to query against document keys in this way. You can search for exact matches using $exists, but you cannot find key names that match a pattern.
I assume (perhaps incorrectly) that you're trying to find documents which have a URL sub-document, and that not all documents will have this? Why not push that type information down a level, something like:
{
payload: {
type: "url",
url: "Facebook.com",
...
}
}
Then you could query like:
db.foo.find({"payload.type": "url", ...})
I would also be remiss if I did not note that you shouldn't use dots (.) is key names in MongoDB. In some cases it's possible to create documents like this, but it will cause great confusions as you attempt to query into embedded documents (where Mongo uses dot as a "path separator" so to speak).
You can do it but you need to use aggregation: Aggregation is pipeline where each stage is applied to each document. You have a wide range of stages to perform various tasks.
I wrote an aggregate pipeline for this specific problem. If you don't need the count but the documents itself you might want to have a look at the $replaceRoot stage.
EDIT: This works only from Mongo v3.4.4 onwards (thanks for the hint #hwase0ng)
db.getCollection('urls').aggregate([
{
// creating a nested array with keys and values
// of the payload subdocument.
// all other fields of the original document
// are removed and only the filed arrayofkeyvalue persists
"$project": {
"arrayofkeyvalue": {
"$objectToArray": "$$ROOT.payload"
}
}
},
{
"$project": {
// extract only the keys of the array
"urlKeys": "$arrayofkeyvalue.k"
}
},
{
// merge all documents
"$group": {
// _id is mandatory and can be set
// in our case to any value
"_id": 1,
// create one big (unfortunately double
// nested) array with the keys
"urls": {
"$push": "$urlKeys"
}
}
},
{
// "explode" the array and create
// one document for each entry
"$unwind": "$urls"
},
{
// "explode" again as the arry
// is nested twice ...
"$unwind": "$urls"
},
{
// now "query" the documents
// with your regex
"$match": {
"urls": {
"$regex": /url_/
}
}
},
{
// finally count the number of
// matched documents
"$count": "count"
}
])

How do I export NHibernate schema for SQLite if I have dots in the schema name?

I'm trying to set up SQLite for unit testing with Fluent NHibernate as shown here but the table names isn't being generated as I expected.
Some tables have schemas with dots inside which seems to break the generation. (Dots works perfectly well with Microsoft SQL Server which I have in my production environment.)
Example:
[Foo.Bar.Schema].[TableName]
Result:
TestFixture failed: System.Data.SQLite.SQLiteException : SQLite error
unknown database Foo
How do I instruct SQLite to translate the dots to underscores or something so I can run my unit tests?
(I've tried adding brackets to the schema names with no success)
You can use a convention
http://wiki.fluentnhibernate.org/Conventions
*UPDATED
public static class PrivatePropertyHelper
{
// from http://stackoverflow.com/questions/1565734/is-it-possible-to-set-private-property-via-reflection
public static T GetPrivatePropertyValue<T>(this object obj, string propName)
{
if (obj == null) throw new ArgumentNullException("obj");
PropertyInfo pi = obj.GetType().GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (pi == null) throw new ArgumentOutOfRangeException("propName", string.Format("Property {0} was not found in Type {1}", propName, obj.GetType().FullName));
return (T)pi.GetValue(obj, null);
}
}
public class CustomTableNameConvention : IClassConvention
{
// Use this to set schema to specific value
public void Apply(FluentNHibernate.Conventions.Instances.IClassInstance instance)
{
instance.Schema("My_NEw_Schema");
instance.Table(instance.EntityType.Name.CamelToUnderscoreLower());
}
// Use this to alter the existing schema value.
// note that Schema is a private property and you need reflection to get it
public void Apply(FluentNHibernate.Conventions.Instances.IClassInstance instance)
{
instance.Schema(instance.GetPrivatePropertyValue<string>("Schema").Replace(".", "_"));
instance.Table(instance.EntityType.Name.CamelToUnderscoreLower());
}
}
You must use only one of he Apply methods.
*UPDATE 2
I don't know I would recommend this but if you like to experiment this seems to work. Even more reflection :)
public static void SetSchemaValue(this object obj, string schema)
{
var mapping_ref = obj.GetType().GetField("mapping", BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.GetField | BindingFlags.NonPublic).GetValue(obj);
var mapping = mapping_ref as ClassMapping;
if (mapping != null)
{
mapping.Schema = schema;
}
}
public void Apply(FluentNHibernate.Conventions.Instances.IClassInstance instance)
{
var schema = instance.GetPrivatePropertyValue<string>("Schema");
if (schema == null)
{
instance.Schema("My_New_Schema");
}
else
{
instance.SetSchemaValue("My_New_Schema");
}
}