Unique index on superclass and value reused between different subclasses - spring-data-neo4j

In a project using Spring Data Neo4j 3.2, I have a model which looks like:
#NodeEntity
public abstract class A {
#GraphId
public Long id;
#Indexed(unique = true)
public Long technicalId;
}
#NodeEntity
public class B extends A {}
#NodeEntity
public class C extends A {}
I missed the paragraph in the documentation talking about the default merge feature, and we ran into the following situation without getting an exception:
B b = new B();
b.technicalId = 42;
neo4jTemplate.save(b);
// I now have Node[1] in Neo4j with the following labels: B, _B, A
C c = new C();
c.technicalId = 42;
neo4jTemplate.save(c);
// No exception and Node[1] now has the following labels: B, _B, A, C, _C
So OK, the situation can be avoided by:
either using instance-based indices:
#NodeEntity
public abstract class A {
#GraphId
public Long id;
#Indexed(unique = true, level = Level.INSTANCE)
public Long technicalId;
}
or using failOnDuplicate (though it's not mentioned in the documentation, even for 3.3, but I found it here and here) which avoids creating 3 indices instead of 1, so less I/Os on writes and less disk space used:
#NodeEntity
public abstract class A {
#GraphId
public Long id;
#Indexed(unique = true, failOnDuplicate = true)
public Long technicalId;
}
However, isn't it a bug that the default behavior will change the nature of the node (when there's a class hierarchy involved) and create a mix of labels which could prevent the instantiation of an entity? I mean the node now has 2 underscore-prefixed labels: n:B:_B:A:C:_C, because the 2 Cypher queries that were executed were:
MERGE (n:`A` {`technicalId`: {value}})
ON CREATE SET n={props} SET n:SupplierCompany
return n
// params {value=42, props={technicalId=42}}
match (n)
where id(n)={nodeId}
set n:`A`:`C`:`_C`
// params {nodeId=1}
Should I raise an issue with a test case on the SDN JIRA or github?

Related

Neo4j RelationshipEntities and cyclic JSON serialization issue with Spring Data Rest

I'm having an issue with serializing #RelationshipEntities to JSON via Spring Data Rest. Whenever I create the #RelationshipEntity, I run into an infinite recursion on serializing the graph to JSON.
Using JSOG to try to render the graph only results in a different, malformed JSON response.
While I can avoid the issue by using #JsonManagedReference, it doesn't solve the problem as I would like to expose the relationship from both nodes.
I've created a simple application that exhibits the issue. It can be found here: https://github.com/cyclomaniac/neo4j-spring-data-rest-cyclic
It implements very basic Team and Player NodeEntities with a single RelationshipEntity, PlayerPosition.
Player:
#NodeEntity
#JsonIdentityInfo(generator= JSOGGenerator.class)
public class Player {
#GraphId
#JsonProperty("id")
private Long id;
private String name;
private String number;
#Relationship(type = "PLAYS_ON")
private PlayerPosition position;
...
Team:
#NodeEntity
#JsonIdentityInfo(generator= JSOGGenerator.class)
public class Team {
#GraphId
#JsonProperty("id")
private Long id;
private String name;
#Relationship(type = "PLAYS_ON", direction = Relationship.INCOMING)
Set<PlayerPosition> teamPlayers;
...
PlayerPosition:
#RelationshipEntity(type="PLAYS_ON")
#JsonIdentityInfo(generator= JSOGGenerator.class)
public class PlayerPosition {
#GraphId
#JsonProperty("id")
private Long id;
private String position;
#StartNode
private Player player;
#EndNode
private Team team;
...
When wired up to a GraphRepository, hitting the /teams endpoint results in the following output with JSOG in place:
{
"_embedded" : {
"teams" : [ {
"#id" : "1",
"name" : "Cubs",
"teamPlayers" : [ {
"#id" : "2",
"position" : "Catcher",
"player" : {
"#id" : "3"
Notice that the JSON ends prematurely. The server throws an exception:
2016-11-04 15:48:03.495 WARN 12287 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to write HTTP message:
org.springframework.http.converter.HttpMessageNotWritableException:
Could not write content: Can not start an object,
expecting field name; nested exception is
com.fasterxml.jackson.core.JsonGenerationException:
Can not start an object, expecting field name
My assumption is that I've chosen a poor way to implement the relationship, though it feels fairly straightforward. I'd appreciate any tips on how I can properly expose this relationship, ideally via Spring Data Rest, from both the Team and Player nodes.
Try to annotate with #JsonIgnore or pair: #JsonBackReference and #JsonManagedReference

Pre-constructor initialization

My problem is like this, I have a class named "Product" and another class named "Agriculture", the "Agriculture" class is inheriting the "Product" class.
When I summon the "Agriculture" constructor obviously the "Product" constructor is summoned first.
The question is, can I initialize one of the product's members via a set method first?
If you have:
class Product { ... };
class Agriculture : public Product { ...};
you can't escape the standard rule that the base object is constructed before the derived object. You have no chance to intervene in this order, nor set anything in Product before it's constructor starts.
Recommendation:
The best design for your need would be to foresee a Product constructor that takes as additional parameter(s) the value(s) that you want to set:
class Product {
string origin;
public:
Product () : origin("tbd") { }
Product (string withorigin) { ...}
void setOrigin (string myorigin) { origin=myorigin; }
};
class Agriculture : public Product {
public:
Agriculture () : Product ("Earth") { ...}
};
Workaround:
If such design would not fit your needs, the only thing you could imagine, would be to have a static member in Product. This member would then be independent of any Product, and could thus be set before an object is constructed.
class Product {
static string defaultCurrency;
string currency;
public:
Product () : currency(defaultCurrency) { ... }
static void setDefaultCurrency (string cur) { defaultCurrency=cur; }
};
class Agriculture : public Product { ... };
int main() {
Product::setDefaultCurrency("EUR");
Agriculture a1;
}
It's more error prone: the construction result depends on order of operations not related to the construction. This could be a problem for example in case of multithreading, if several threads construct objects at same moment.
Product constructor is called firstly, and you set some values inside this constructor. So why you still want to initialize one of the product's members via a set method first?

Sitecore Glass data model inheritence

I am using the Glass Mapper on a Sitecore instance where I have a basic data template structure of
Base
BaseWithList
BaseWithExtraContent
BaseWithExtraContentAndCallToActionLink
I have added model classes in my project to follow this structure too. My class names match my template names.
[SitecoreType(TemplateId = "{5D19BD92-799E-4DC1-9A4E-1DDE3AD68DAD}", AutoMap = true)]
public class Base
{
public virtual string Title {get;set;}
public virtual string Content {get;set;}
}
[SitecoreType(TemplateId = "{0491E3D6-EBAA-4E21-B255-80F0607B176D}", AutoMap = true)]
public class BaseWithExtraContent : Base
{
public virtual string ExtraContent {get;set;}
}
[SitecoreType(TemplateId = "{95563412-7A08-46A3-98CB-ABC4796D57D4}", AutoMap = true)]
public class BaseWithExtraContentAndCallToActionLink : BaseWithExtraContent
{
public virtual string CallToActionLink {get;set;}
}
These data models are used from another class that has a list of base type, I want to be able to store any derived type in here so I added attributes as detailed in this tutorial
[SitecoreType(AutoMap = true)]
public class HomePage
{
[SitecoreChildren(InferType = true)]
[SitecoreField(FieldName = "Widgets")]
public virtual IEnumerable<Base> Widgets { get; set; }
}
According to the tutorial this should work. However the list of widget just contains class of the base type.
I then found a later tutorial that said that if you have separated out the models to a different assemblies than the one Glass is installed in you have to add an AttributeConfigurationLoader pointing to the assembly your models are in. The base and derived types are all in the same assembly so I wasn't sure this would solve the issue, but I tried it anyway.
My custom loader config looks like this:
public static class GlassMapperScCustom
{
public static void CastleConfig(IWindsorContainer container)
{
var config = new Config {UseWindsorContructor = true};
container.Install(new SitecoreInstaller(config));
}
public static IConfigurationLoader[] GlassLoaders()
{
var attributes = new AttributeConfigurationLoader("Project.Data");
return new IConfigurationLoader[] {attributes};
}
public static void PostLoad(){
//Remove the comments to activate CodeFist
/* CODE FIRST START
var dbs = Sitecore.Configuration.Factory.GetDatabases();
foreach (var db in dbs)
{
var provider = db.GetDataProviders().FirstOrDefault(x => x is GlassDataProvider) as GlassDataProvider;
if (provider != null)
{
using (new SecurityDisabler())
{
provider.Initialise(db);
}
}
}
* CODE FIRST END
*/
}
}
Upon doing the custom loader config I now get an "Ambiguous match found" exception. I have checked to see if there are any other non Glass attributes set in the classes in that assembly and there aren't.
Any ideas? I guess there are 2 questions.
Why does using the inferred type attribute not load the correct types and only the base types?
Why when I attempt to solve this by adding a custom attribute loader do I get the exception?
Widgets property has two attributes - it's either mapped to the children elements of the item, or a field, can't be both.

Why is AutoFixture Customization causing inherited properties to not be filled?

I wrote the following customization and have it applied as part of a composite on most of my tests. My entities have a read-only Id, but I'm using their SetId method in this customization to make sure all entities have some Id if they are transient (don't have an Id already).
public class SetEntityIdCustomization : ICustomization {
public void Customize(IFixture fixture) {
var engine = ((Fixture)fixture).Engine;
fixture.Customizations.Add(new Postprocessor(
engine, o => {
var entity = o as BaseEntity;
if (entity == null || !entity.IsTransient()) {
return;
}
entity.SetId(fixture.CreateAnonymous<Guid>());
}));
}
}
This has been working great, until I discovered a very odd thing today. If I feed a test one of my entities that directly inherits from BaseEntity, all is well and it's writeable properties are auto-filled. However, if I ask for an entity that inherits from something further down from BaseEntity, my customization prevents the properties from auto-filling.
The User entity in this test method is filled properly:
public class User : BaseEntity {
public string Email { get; set; }
public int CoolThings { get; set; }
}
...
[Theory, AutoDomainData]
public void SomeTest(User user, ...) {
// user.Email and user.CoolThings have auto-filled values, as expected.
...
}
However, the AwesomeUser entity in the following test does not get any of the same properties auto-filled.
public class AwesomeUser : User {
...
}
...
[Theory, AutoDomainData]
public void SomeOtherTest(AwesomeUser user, ...) {
// user.Email nor user.CoolThings have auto-filled values. What gives?
...
}
In both test cases, the Id property is auto-filled because of my customization. If I remove my customization, the SomeOtherTest's AwesomeUser instance gets its inherited properties auto-filled just fine. I must assume that my customization is what is messing things up.
Is there a better way to get all my BaseEntity instances to set their Id, or is there something else I'm missing with AutoFixture? I've applied my customization first, in the middle, and last, to no avail.
The solution provided above is a pretty clever attempt, but not something I've seen before. A more idiomatic solution would be something like this:
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(
new FilteringSpecimenBuilder(
new Postprocessor(
new BaseEntityBuilder(
new ConstructorInvoker(
new ModestConstructorQuery())),
new AutoPropertiesCommand().Execute),
new BaseEntitySpecification()));
}
private class BaseEntityBuilder : ISpecimenBuilder
{
private readonly ISpecimenBuilder builder;
private readonly IRequestSpecification specification;
public BaseEntityBuilder(ISpecimenBuilder builder)
{
this.builder = builder;
this.specification = new BaseEntitySpecification();
}
public object Create(object request, ISpecimenContext context)
{
if (!this.specification.IsSatisfiedBy(request))
return new NoSpecimen(request);
var b = (BaseEntity)this.builder.Create(request, context);
b.SetId((Guid)context.Resolve(typeof(Guid)));
return b;
}
}
private class BaseEntitySpecification : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
{
var t = request as Type;
if (t == null)
return false;
if (!typeof(BaseEntity).IsAssignableFrom(t))
return false;
return true;
}
}
As you can see, this isn't a simple one-liner, which is indicative of AutoFixture being a rather opinionated library. In this case, AutoFixture's opinion is:
Favor object composition over class inheritance.
-Design Patterns, p. 20
AutoFixture is first and foremost a TDD tool, and one of the main advantages of TDD is that it provides feedback about class design. In this case, the feedback is: Inheritance is awkward and troublesome. Reconsider the design.

Should class methods accept parameters or use class properties

Consider the following class
public class Class1
{
public int A { get; set; }
public int B { get; set; }
public int GetComplexResult()
{
return A + B;
}
}
In order to use GetComplexResult, a consumer of this class would have to know to set A and B before calling the method. If GetComplexResult accesses many properties to calculate its result, this can lead to wrong return values if the consumer doesn't set all the appropriate properties first. So you might write this class like this instead
public class Class2
{
public int A { get; set; }
public int B { get; set; }
public int GetComplexResult(int a, int b)
{
return a + b;
}
}
This way, a caller to GetComplexResult is forced to pass in all the required values, ensuring the expected return value is correctly calculated. But if there are many required values, the parameter list grows as well and this doesn't seem like good design either. It also seems to break the point of encapsulating A, B and GetComplexResult in a single class. I might even be tempted to make GetComplexResult static since it doesn't require an instance of the class to do its work. I don't want to go around making a bunch of static methods.
Are there terms to describe these 2 different ways of creating classes? They both seem to have pros and cons - is there something I'm not understanding that should tell me that one way is better than the other? How does unit testing influence this choice?
If you use a real-world example the answer becomes clearer.
public class person
{
public string firstName { get; set; }
public string lastName { get; set; }
public string getFullName()
{
return firstName + " " + lastName;
}
}
The point of an entity object is that it contains information about an entity, and can do the operations that the entity needs to do (based on the information it contains). So yes, there are situations in which certain operations won't work properly because the entity hasn't been fully initialized, but that's not a failure of design. If, in the real world, I ask you for the full name of a newborn baby who hasn't been named yet, that will fail also.
If certain properties are essential to an entity doing its job, they can be initialized in a constructor. Another approach is to have a boolean that checks whether the entity is in a state where a given method can be called:
while (person.hasAnotherQuestion()) {
person.answerNextQuestion();
}
A good design rule is to make sure that all constructors initializes objects to valid states and that all property setters and methods then enforces the valid state. This way there will never be any objects in invalid states.
If the default values for A and B, which is 0 is not a valid state that yields a valid result from GetComplexResult, you should a constructor that initialized A and B to valid a state.
If some of the fields are never allowed to be null then you would typically make them parameters to the class constructor. If you don't always have all of the required values available at once then using a builder class may be helpful.
For example:
public Builder {
private int a;
private int b;
public Class1 create() {
// some validation logic goes here
// to make sure we have everything and
// either fill in defaults or throw an error
// if needed
return new Class1(a, b)
}
public Builder a(int val) { a = val; }
public Builder b(int val) { b = val; }
}
This Builder can then be used as follows.
Class1 obj1 = new Builder().a(5).b(6).create();
Builder builder = new Builder();
// do stuff to find value of a
builder.a(valueOfA);
// do stuff to find value of b
builder.b(valueOfB);
// do more stuff
Class1 obj2 = builder.create();
Class2 obj3 = builder.create();
This design allows you to lock down the Entity classes to whatever degree is appropriate while still allowing for a flexible construction process. It also opens the door to customizing the construction process with other implementations without changing the entity class contract.