diff --git a/pom.xml b/pom.xml
index faa08f02..bca1bad3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,8 +11,8 @@
graph-corejar
- 2.0.9
- Graph Core Next Generation
+ 2.0.10-SNAPSHOT
+ Graph Core
The Reactome Graph Project aims to model the Reactome knowledgebase into a interconnected graph. For more
@@ -111,6 +111,12 @@
jackson-databindtest
+
+ com.voodoodyne.jackson.jsog
+ jackson-jsog
+ 1.1.2
+ test
+
@@ -119,7 +125,7 @@
src/main/resources
- false
+ true
@@ -249,6 +255,20 @@
maven-source-plugin${maven.source.version}
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ ${maven.source.version}
+
+
+ attach-sources
+
+ jar
+
+
+
+
diff --git a/src/main/java/org/reactome/server/graph/aop/README.md b/src/main/java/org/reactome/server/graph/aop/README.md
index 5b6a9bb7..28046725 100644
--- a/src/main/java/org/reactome/server/graph/aop/README.md
+++ b/src/main/java/org/reactome/server/graph/aop/README.md
@@ -1,18 +1,18 @@
-Aspect-Oriented Programming with Spring
+Aspect Oriented Programming with Spring
===
:warning: Changes in this package have to be taken carefully, considering it is going to reflect in the whole application
### What is Aspect-Oriented Programming - AOP?
-Spring AOP framework is used to modularize cross-cutting concerns in aspects. Simply, it’s just an interceptor to intercept some processes, for example, when a method is executed, Spring AOP can hijack the executing method, and add extra functionality before or after the method execution. The most used feature is logging.
+Spring AOP framework is used to modularize cross-cutting concerns in aspects. Simply, t’s just an interceptor to intercept some processes, for example, when a method is execute, Spring AOP can hijack the executing method, and add extra functionality before or after the method execution. The most used feature is logging.
However, in Reactome, we are taking benefit of this concept in order to implement our own Lazy-Loading mechanism. This functionality is also available in ORM frameworks, such as, Hibernate and to achieve this they are implementing AOP concepts. Sorting and Logging aspect are present as well.
-Complete information on Spring AOP you'll find [here](https://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html).
+Complete information of Spring AOP you'll find [here](https://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html).
-### What are the `@PointCut` in Reactome for LazyLoading?
+### What are the `@PointCut` in Reactome for LazyLoading ?
```java
execution(public java.util.Collection+ org.reactome.server.graph.domain.model.*.get*(..))
@@ -24,7 +24,7 @@ execution(public org.reactome.server.graph.domain.model.DatabaseObject+ org.reac
```
Intercepting ALL the getters in our Domain Model whose return type is `DatabaseObject` or `instance of`
-### How does it work?
+### How does it work ?
Mainly, we are loading DEPTH{2} data from the graph without any relationship previously loaded, only identifiers. Once intercepted, the code checks whether the AOP is enabled and whether the object has been loaded previously. Substantially using Java Reflection, the code is capable to identify all the information regarding the method that has been intercepted, for instance, return type (`Collection` or `DatabaseObject`) and `@Relationship` which contains important information for querying against the Graph. Up to this point, the data have been retrieve and the code invokes the setter and proceed.
@@ -95,19 +95,19 @@ public LazyFetchAspect lazyFetchAspect() {
```
-#### What is the flag `enableAOP`?
+#### What is the flag `enableAOP` ?
-The AOP is enabled by default, but in certain projects like [Content Service](https://github.com/reactome/content-service.git) where we respond a serialised JSON, the `@PointCut` will be invoked everywhere, every time, endless times. Thus, given the `Content Service` requirements, it makes sense that we disable this feature. However, we kept it enabled in the [Data Content](https://github.com/reactome/data-content).
+The AOP is enabled by default, but in certain projects like [Content Service](https://github.com/reactome/content-service.git) where we respond a serialised JSON, the `@PointCut` will be invoked every where, every time, endless times. Thus, given the requirements of the `Content Service` it makes sense that we disable this feature. However, in the [Data Content](https://github.com/reactome/data-content) we kept it enabled.
=
-### SortingAspect?
+### SortingAspect ?
Intercepting ALL the getters in our Domain Model whose return type is `Collection extends DatabaseObject>` and sorting the list based on the `displayName`.
=
-### LoggingAspect?
+### LoggingAspect ?
-Logging everything at the service level. The package `service` is being intercepted to measure the execution time.
+Logging everything at the service level. The package `service` is being intercepted in order to measure the execution time.
\ No newline at end of file
diff --git a/src/main/java/org/reactome/server/graph/domain/annotations/StoichiometryView.java b/src/main/java/org/reactome/server/graph/domain/annotations/StoichiometryView.java
new file mode 100644
index 00000000..9745de33
--- /dev/null
+++ b/src/main/java/org/reactome/server/graph/domain/annotations/StoichiometryView.java
@@ -0,0 +1,10 @@
+package org.reactome.server.graph.domain.annotations;
+
+public class StoichiometryView {
+
+ public interface Flatten { }
+
+ public interface Nested { }
+
+ public interface NestedAggregated extends Nested { }
+}
\ No newline at end of file
diff --git a/src/main/java/org/reactome/server/graph/domain/model/AbstractModifiedResidue.java b/src/main/java/org/reactome/server/graph/domain/model/AbstractModifiedResidue.java
index 5fad195f..d51ebcca 100644
--- a/src/main/java/org/reactome/server/graph/domain/model/AbstractModifiedResidue.java
+++ b/src/main/java/org/reactome/server/graph/domain/model/AbstractModifiedResidue.java
@@ -3,11 +3,12 @@
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Relationship;
+
@SuppressWarnings("unused")
@Node
public abstract class AbstractModifiedResidue extends DatabaseObject {
- @Relationship(type = "referenceSequence")
+ @Relationship(type = Relationships.REFERENCE_SEQUENCE)
private ReferenceSequence referenceSequence;
public AbstractModifiedResidue() {}
diff --git a/src/main/java/org/reactome/server/graph/domain/model/BlackBoxEvent.java b/src/main/java/org/reactome/server/graph/domain/model/BlackBoxEvent.java
index d818e7e8..7550dc87 100644
--- a/src/main/java/org/reactome/server/graph/domain/model/BlackBoxEvent.java
+++ b/src/main/java/org/reactome/server/graph/domain/model/BlackBoxEvent.java
@@ -19,7 +19,7 @@ public String getExplanation() {
}
- @Relationship(type = "templateEvent")
+ @Relationship(type = Relationships.TEMPLATE_EVENT)
private Event templateEvent;
public BlackBoxEvent() {}
diff --git a/src/main/java/org/reactome/server/graph/domain/model/Book.java b/src/main/java/org/reactome/server/graph/domain/model/Book.java
index a782d0b7..7d78dfde 100644
--- a/src/main/java/org/reactome/server/graph/domain/model/Book.java
+++ b/src/main/java/org/reactome/server/graph/domain/model/Book.java
@@ -17,7 +17,7 @@ public class Book extends Publication {
@ReactomeProperty
private Integer year;
- @Relationship(type = "publisher")
+ @Relationship(type = Relationships.PUBLISHER)
private Affiliation publisher;
public Book() {}
diff --git a/src/main/java/org/reactome/server/graph/domain/model/CandidateSet.java b/src/main/java/org/reactome/server/graph/domain/model/CandidateSet.java
index c7c03581..25b63d09 100644
--- a/src/main/java/org/reactome/server/graph/domain/model/CandidateSet.java
+++ b/src/main/java/org/reactome/server/graph/domain/model/CandidateSet.java
@@ -1,50 +1,55 @@
package org.reactome.server.graph.domain.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonView;
import org.reactome.server.graph.domain.annotations.ReactomeSchemaIgnore;
+import org.reactome.server.graph.domain.annotations.StoichiometryView;
+import org.reactome.server.graph.domain.relationship.Has;
import org.reactome.server.graph.domain.relationship.HasCandidate;
+import org.reactome.server.graph.domain.relationship.CompositionAggregator;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Relationship;
import java.util.*;
+import java.util.stream.Stream;
/**
* A set of entities that are interchangeable in function, with two subclasses, members that are hypothetical and members that have been demonstrated. Hypothetical members are identified as values of the hasCandidate slot. Members that have been demonstrated are identified in the hasMember slot. At least one hasCandidate value is required; hasMember values are optional.
*/
@SuppressWarnings("unused")
@Node
-public class CandidateSet extends EntitySet {
+public class CandidateSet extends EntitySet implements CompositionAggregator {
- @Relationship(type = "hasCandidate")
+ @Relationship(type = Relationships.HAS_CANDIDATE)
private SortedSet hasCandidate;
- public CandidateSet() {}
+ @Override
+ public Stream extends Collection extends Has extends DatabaseObject>>> defineCompositionRelations() {
+ return Stream.concat(super.defineCompositionRelations(), Stream.of(hasCandidate));
+ }
+
+ public CandidateSet() {
+ }
+
+ @ReactomeSchemaIgnore
+ @JsonView(StoichiometryView.Nested.class)
+ public SortedSet getCandidates() {
+ return hasCandidate;
+ }
+
+ @JsonView(StoichiometryView.Nested.class)
+ public void setCandidates(SortedSet hasCandidate) {
+ this.hasCandidate = hasCandidate;
+ }
+ @JsonView(StoichiometryView.Flatten.class)
public List getHasCandidate() {
- List rtn = null;
- if (hasCandidate != null) {
- rtn = new ArrayList<>();
- //stoichiometry does NOT need to be taken into account here
- for (HasCandidate candidate : hasCandidate) {
- rtn.add(candidate.getPhysicalEntity());
- }
- }
- return rtn;
+ return Has.Util.expandStoichiometry(this.hasCandidate);
}
+ @JsonView(StoichiometryView.Flatten.class)
public void setHasCandidate(List hasCandidate) {
- if (hasCandidate == null) return;
- Map components = new LinkedHashMap<>();
- int order = 0;
- for (PhysicalEntity physicalEntity : hasCandidate) {
- //stoichiometry does NOT need to be taken into account here
- HasCandidate aux = new HasCandidate();
-// aux.setEntitySet(this);
- aux.setPhysicalEntity(physicalEntity);
- aux.setOrder(order++);
- components.put(physicalEntity.getDbId(), aux);
- }
- this.hasCandidate = new TreeSet<>(components.values());
+ this.hasCandidate = Has.Util.aggregateStoichiometry(hasCandidate, HasCandidate::new);
}
@ReactomeSchemaIgnore
diff --git a/src/main/java/org/reactome/server/graph/domain/model/CatalystActivity.java b/src/main/java/org/reactome/server/graph/domain/model/CatalystActivity.java
index 51acb21e..0d8916ec 100644
--- a/src/main/java/org/reactome/server/graph/domain/model/CatalystActivity.java
+++ b/src/main/java/org/reactome/server/graph/domain/model/CatalystActivity.java
@@ -15,10 +15,10 @@
@Node
public class CatalystActivity extends DatabaseObject {
- @Relationship(type = "activeUnit")
+ @Relationship(type = Relationships.ACTIVE_UNIT)
private Set activeUnit;
- @Relationship(type = "activity")
+ @Relationship(type = Relationships.ACTIVITY)
private GO_MolecularFunction activity;
/**
@@ -26,13 +26,13 @@ public class CatalystActivity extends DatabaseObject {
*/
@JsonIgnore
@ReactomeTransient
- @Relationship(type = "catalystActivity", direction = Relationship.Direction.INCOMING)
+ @Relationship(type = Relationships.CATALYST_ACTIVITY, direction = Relationship.Direction.INCOMING)
private List catalyzedEvent;
- @Relationship(type = "physicalEntity")
+ @Relationship(type = Relationships.PHYSICAL_ENTITY)
private PhysicalEntity physicalEntity;
- @Relationship(type = "literatureReference")
+ @Relationship(type = Relationships.LITERATURE_REFERENCE)
private List literatureReference;
public CatalystActivity() {}
diff --git a/src/main/java/org/reactome/server/graph/domain/model/Cell.java b/src/main/java/org/reactome/server/graph/domain/model/Cell.java
index c685ef85..2bf573cb 100644
--- a/src/main/java/org/reactome/server/graph/domain/model/Cell.java
+++ b/src/main/java/org/reactome/server/graph/domain/model/Cell.java
@@ -1,34 +1,47 @@
package org.reactome.server.graph.domain.model;
import com.fasterxml.jackson.annotation.JsonGetter;
+import org.reactome.server.graph.domain.relationship.CompositionAggregator;
+import org.reactome.server.graph.domain.relationship.Has;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Relationship;
+import java.util.Collection;
import java.util.List;
+import java.util.Objects;
+import java.util.stream.Stream;
@Node
-public class Cell extends PhysicalEntity {
- @Relationship(type = "RNAMarker")
+public class Cell extends PhysicalEntity implements CompositionAggregator {
+ @Relationship(type = Relationships.RNA_MARKER)
private List RNAMarker;
- @Relationship(type = "markerReference")
+ @Relationship(type = Relationships.MARKER_REFERENCE)
private List markerReference;
- @Relationship(type = "organ")
+ @Relationship(type = Relationships.ORGAN)
private Anatomy organ;
- @Relationship(type = "proteinMarker")
+ @Relationship(type = Relationships.PROTEIN_MARKER)
private List proteinMarker;
- @Relationship(type = "species")
+ @Relationship(type = Relationships.SPECIES)
private List species;
- @Relationship(type = "tissue")
+ @Relationship(type = Relationships.TISSUE)
private Anatomy tissue;
- @Relationship(type = "tissueLayer")
+ @Relationship(type = Relationships.TISSUE_LAYER)
private Anatomy tissueLayer;
+ @Override
+ public Stream extends Collection extends Has extends DatabaseObject>>> defineCompositionRelations() {
+ return Stream.of(
+ Has.Util.wrapUniqueElements(RNAMarker, "rnaMarker"),
+ Has.Util.wrapUniqueElements(proteinMarker, "proteinMarker")
+ );
+ }
+
public Cell() {
}
diff --git a/src/main/java/org/reactome/server/graph/domain/model/Complex.java b/src/main/java/org/reactome/server/graph/domain/model/Complex.java
index 6c8266ee..660862e9 100644
--- a/src/main/java/org/reactome/server/graph/domain/model/Complex.java
+++ b/src/main/java/org/reactome/server/graph/domain/model/Complex.java
@@ -1,45 +1,55 @@
package org.reactome.server.graph.domain.model;
-import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.*;
import org.reactome.server.graph.domain.annotations.ReactomeProperty;
import org.reactome.server.graph.domain.annotations.ReactomeSchemaIgnore;
+import org.reactome.server.graph.domain.annotations.StoichiometryView;
+import org.reactome.server.graph.domain.relationship.Has;
import org.reactome.server.graph.domain.relationship.HasCompartment;
import org.reactome.server.graph.domain.relationship.HasComponent;
+import org.reactome.server.graph.domain.relationship.CompositionAggregator;
import org.reactome.server.graph.service.helper.StoichiometryObject;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Relationship;
import java.util.*;
+import java.util.stream.Stream;
/**
* An entity formed by the association of two or more component entities (these components can themselves be complexes). Complexes represent all experimentally verified components and their stoichiometry where this is known but may not include as yet unidentified components. At least one component must be specified.
*/
@SuppressWarnings("unused")
@Node
-public class Complex extends PhysicalEntity {
+public class Complex extends PhysicalEntity implements CompositionAggregator {
@ReactomeProperty
private Boolean isChimeric;
- @Relationship(type = "hasComponent")
+ @Relationship(type = Relationships.HAS_COMPONENT)
private SortedSet hasComponent;
@ReactomeProperty
private Boolean stoichiometryKnown;
- @Relationship(type = "entityOnOtherCell")
+ @Relationship(type = Relationships.ENTITY_ON_OTHER_CELL)
private List entityOnOtherCell;
- @Relationship(type = "includedLocation")
+ @Relationship(type = Relationships.INCLUDED_LOCATION)
private SortedSet includedLocation;
- @Relationship(type = "species")
+ @Relationship(type = Relationships.SPECIES)
private List species;
- @Relationship(type = "relatedSpecies")
+ @Relationship(type = Relationships.RELATED_SPECIES)
private List relatedSpecies;
- public Complex() {}
+ @Override
+ public Stream extends Collection extends Has extends DatabaseObject>>> defineCompositionRelations() {
+ return Stream.of(hasComponent);
+ }
+
+ public Complex() {
+ }
public Complex(Long dbId) {
super(dbId);
@@ -55,46 +65,28 @@ public void setIsChimeric(Boolean isChimeric) {
@JsonIgnore
public List fetchHasComponent() {
- List objects = new ArrayList<>();
- if(hasComponent!=null) {
- for (HasComponent aux : hasComponent) {
- objects.add(new StoichiometryObject(aux.getStoichiometry(), aux.getPhysicalEntity()));
- }
- Collections.sort(objects);
- }
-
- return objects;
- }
-
- public List getHasComponent(){
- List rtn = null;
- if (this.hasComponent != null) {
- rtn = new ArrayList<>();
- for (HasComponent component : this.hasComponent) {
- for (int i = 0; i < component.getStoichiometry(); i++) {
- rtn.add(component.getPhysicalEntity());
- }
- }
- }
- return rtn;
+ return Has.Util.simplifiedSort(this.hasComponent);
+ }
+
+ @ReactomeSchemaIgnore
+ @JsonView(StoichiometryView.Nested.class)
+ public SortedSet getComponents() {
+ return this.hasComponent;
+ }
+
+ @JsonView(StoichiometryView.Nested.class)
+ public void setHasComponentNested(Collection hasComponent) {
+ this.hasComponent = new TreeSet<>(hasComponent);
+ }
+
+ @JsonView(StoichiometryView.Flatten.class)
+ public List getHasComponent() {
+ return Has.Util.expandStoichiometry(this.hasComponent);
}
+ @JsonView(StoichiometryView.Flatten.class)
public void setHasComponent(List hasComponent) {
- if (hasComponent == null) return;
- Map components = new LinkedHashMap<>();
- int order = 0;
- for (PhysicalEntity physicalEntity : hasComponent) {
- HasComponent component = components.get(physicalEntity.getDbId());
- if (component != null) {
- component.setStoichiometry(component.getStoichiometry() + 1);
- } else {
- component = new HasComponent();
- component.setPhysicalEntity(physicalEntity);
- component.setOrder(order++);
- components.put(physicalEntity.getDbId(), component);
- }
- }
- this.hasComponent = new TreeSet<>(components.values());
+ this.hasComponent = Has.Util.aggregateStoichiometry(hasComponent, HasComponent::new);
}
public Boolean getStoichiometryKnown() {
@@ -114,12 +106,7 @@ public void setEntityOnOtherCell(List entityOnOtherCell) {
}
public List getIncludedLocation() {
- if (includedLocation == null) return null;
- List rtn = new ArrayList<>();
- for (HasCompartment c : includedLocation) {
- rtn.add(c.getCompartment());
- }
- return rtn;
+ return Has.Util.expandStoichiometry(includedLocation);
}
public void setIncludedLocation(SortedSet includedLocation) {
@@ -127,14 +114,7 @@ public void setIncludedLocation(SortedSet includedLocation) {
}
public void setIncludedLocation(List includedLocation) {
- this.includedLocation = new TreeSet<>();
- int order = 0;
- for (Compartment c : includedLocation) {
- HasCompartment hc = new HasCompartment();
- hc.setCompartment(c);
- hc.setOrder(order++);
- this.includedLocation.add(hc);
- }
+ this.includedLocation = Has.Util.aggregateStoichiometry(includedLocation, HasCompartment::new);
}
public List getSpecies() {
diff --git a/src/main/java/org/reactome/server/graph/domain/model/DatabaseIdentifier.java b/src/main/java/org/reactome/server/graph/domain/model/DatabaseIdentifier.java
index f8039662..5b60e64b 100644
--- a/src/main/java/org/reactome/server/graph/domain/model/DatabaseIdentifier.java
+++ b/src/main/java/org/reactome/server/graph/domain/model/DatabaseIdentifier.java
@@ -17,10 +17,10 @@ public class DatabaseIdentifier extends DatabaseObject {
@ReactomeProperty(addedField = true)
private String url;
- @Relationship(type = "crossReference")
+ @Relationship(type = Relationships.CROSS_REFERENCE)
private List crossReference;
- @Relationship(type = "referenceDatabase")
+ @Relationship(type = Relationships.REFERENCE_DATABASE)
private ReferenceDatabase referenceDatabase;
public DatabaseIdentifier() {}
diff --git a/src/main/java/org/reactome/server/graph/domain/model/DatabaseObject.java b/src/main/java/org/reactome/server/graph/domain/model/DatabaseObject.java
index 139eb1c5..49aa0399 100644
--- a/src/main/java/org/reactome/server/graph/domain/model/DatabaseObject.java
+++ b/src/main/java/org/reactome/server/graph/domain/model/DatabaseObject.java
@@ -15,7 +15,6 @@
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
@@ -57,10 +56,10 @@ public abstract class DatabaseObject implements Serializable, Comparable T preventLazyLoading(boolean preventLazyLoadin
}
if (Collection.class.isAssignableFrom(methodReturnClazz)) {
- ParameterizedType stringListType = (ParameterizedType) method.getGenericReturnType();
- Class> type = (Class>) stringListType.getActualTypeArguments()[0];
- String clazz = type.getSimpleName();
- if (DatabaseObject.class.isAssignableFrom(type)) {
- Collection collection = (Collection) method.invoke(this);
- if (collection != null) {
- for (DatabaseObject obj : collection) {
- DatabaseObject object = obj;
- if (object != null) {
- if (object.preventLazyLoading == null) {
- object.preventLazyLoading = false;
- }
- if (object.preventLazyLoading != preventLazyLoading) {
- object.preventLazyLoading(preventLazyLoading);
- }
- }
- }
+ Collection