diff --git a/CHANGELOG.md b/CHANGELOG.md index cee5412f63f5b10e3d6d8bc18e0bafc91b0efb02..60b3727bdde8cf0cc07e9f083cdac45d563f48b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,11 @@ # Ferma Changelog -## 3.1.1 +## 3.2.0 * Added nexus staging deployment plugin. * Removed explicit version from licensing plugin. * Pom updated to require maven 3.0.4 +* Added additional constructor to DelegatingFramedGraph which accepts a package name to scan instead of needing to explicitly pass all the model's classes as a set. ## 3.1.0 diff --git a/pom.xml b/pom.xml index 805dc80576670255ce0a56dec4354999208ab255..724621bcbb2f94b2a3b26434de1814bf63201b89 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ <groupId>com.syncleus.ferma</groupId> <artifactId>ferma</artifactId> <packaging>jar</packaging> - <version>3.1.1-SNAPSHOT</version> + <version>3.2.0-SNAPSHOT</version> <prerequisites> <maven>3.0.4</maven> diff --git a/src/main/java/com/syncleus/ferma/DelegatingFramedGraph.java b/src/main/java/com/syncleus/ferma/DelegatingFramedGraph.java index 8a12aec59d5a712875897089a9558cedb21e450f..1a2d5f5911c426a1f4c3d9d03aee50eef4062b56 100644 --- a/src/main/java/com/syncleus/ferma/DelegatingFramedGraph.java +++ b/src/main/java/com/syncleus/ferma/DelegatingFramedGraph.java @@ -170,15 +170,19 @@ public class DelegatingFramedGraph<G extends Graph> implements WrappedFramedGrap * The types to be consider for type resolution. */ public DelegatingFramedGraph(final G delegate, final Collection<? extends Class<?>> types) { - this.delegate = delegate; - - if( types == null ) - throw new IllegalArgumentException("types can not be null"); + this(delegate, new ReflectionCache(types), true, true); + } - final ReflectionCache reflections = new ReflectionCache(types); - this.defaultResolver = new PolymorphicTypeResolver(reflections); - this.untypedResolver = new UntypedTypeResolver(); - this.builder = new AnnotationFrameFactory(reflections); + /** + * Construct a Typed framed graph with the specified type resolution and with annotation support + * + * @param delegate + * The graph to wrap. + * @param modelPackage + * The package scanned for classes to be considered for type resolution. + */ + public DelegatingFramedGraph(final G delegate, final String modelPackage) { + this(delegate, new ReflectionCache(modelPackage), true, true); } /** diff --git a/src/main/java/com/syncleus/ferma/ReflectionCache.java b/src/main/java/com/syncleus/ferma/ReflectionCache.java index 8e640c88733b0635f234333157d758cebbd00454..3d2c735ae6d723c57bd251d75cdba56b815f50bf 100644 --- a/src/main/java/com/syncleus/ferma/ReflectionCache.java +++ b/src/main/java/com/syncleus/ferma/ReflectionCache.java @@ -15,6 +15,7 @@ */ package com.syncleus.ferma; +import com.syncleus.ferma.annotations.GraphElement; import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; import org.reflections.scanners.TypeAnnotationsScanner; @@ -44,6 +45,12 @@ public class ReflectionCache extends Reflections { this.hierarchy = constructHierarchy(annotatedTypes); } + public ReflectionCache(final String modelPackage) { + super(modelPackage); + + this.hierarchy = constructHierarchy(this.getTypesAnnotatedWith(GraphElement.class)); + } + public Set<? extends String> getSubTypeNames(final Class<?> type) { Set<String> subtypes = this.hierarchy.get(type.getName()); if (subtypes == null) diff --git a/src/test/java/com/syncleus/ferma/Person.java b/src/test/java/com/syncleus/ferma/Person.java index 108cbf9be94073dfa984fc75245986150b33d2d1..68589e241b3418ebe25487530a8f2bf7ecde966d 100644 --- a/src/test/java/com/syncleus/ferma/Person.java +++ b/src/test/java/com/syncleus/ferma/Person.java @@ -17,6 +17,7 @@ package com.syncleus.ferma; import java.util.function.Function; import com.google.common.collect.Lists; +import com.syncleus.ferma.annotations.GraphElement; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.structure.Element; import org.apache.tinkerpop.gremlin.structure.Vertex; @@ -25,6 +26,7 @@ import javax.annotation.Nullable; import java.util.Iterator; import java.util.List; +@GraphElement public class Person extends AbstractVertexFrame { static final ClassInitializer<Person> DEFAULT_INITIALIZER = new DefaultClassInitializer(Person.class); diff --git a/src/test/java/com/syncleus/ferma/PolymorphicTypeResolverTest.java b/src/test/java/com/syncleus/ferma/PolymorphicTypeResolverTest.java index dd671de44d8aa0717dab32f045843274f17af4cc..5b9f24215f54e77e1ac8244d406a8525ccb110f8 100644 --- a/src/test/java/com/syncleus/ferma/PolymorphicTypeResolverTest.java +++ b/src/test/java/com/syncleus/ferma/PolymorphicTypeResolverTest.java @@ -16,6 +16,9 @@ package com.syncleus.ferma; import java.util.function.Function; + +import com.syncleus.ferma.annotations.God; +import com.syncleus.ferma.annotations.GodExtended; import com.syncleus.ferma.typeresolvers.PolymorphicTypeResolver; import com.syncleus.ferma.framefactories.annotation.AnnotationFrameFactory; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; @@ -32,6 +35,7 @@ import java.util.*; public class PolymorphicTypeResolverTest { private static final Set<Class<?>> TEST_TYPES = new HashSet<>(Arrays.asList(new Class<?>[]{Person.class, Programmer.class})); + private static final String TEST_MODEL_PACKAGE = "com.syncleus.ferma"; private static final String CUSTOM_TYPE_KEY = "some_custom_type_key"; @Test @@ -53,6 +57,67 @@ public class PolymorphicTypeResolverTest { final Person person = framedGraph.traverse(input -> input.V()).next(Person.class); Assert.assertFalse(person instanceof Programmer); } + + @Test + public void testHasTypeParentFromPackage() { + final Graph godGraph = TinkerGraph.open(); + final FramedGraph framedGraph = new DelegatingFramedGraph(godGraph, TEST_MODEL_PACKAGE); + + //add a single node to the graph, a programmer. + framedGraph.addFramedVertex(Programmer.class); + + //make sure the newly added node is actually a programmer + final Person programmer = framedGraph.traverse(input -> framedGraph.getTypeResolver().hasType(input.V(), Person.class)).next(Person.class); + Assert.assertTrue(programmer instanceof Programmer); + + //change the type resolution to person + programmer.setTypeResolution(Person.class); + + //make sure the newly added node is not actually a programmer + final Person person = framedGraph.traverse(input -> input.V()).next(Person.class); + Assert.assertFalse(person instanceof Programmer); + } + + @Test + public void testHasTypeChildFromPackage() { + final Graph godGraph = TinkerGraph.open(); + final FramedGraph framedGraph = new DelegatingFramedGraph(godGraph, TEST_MODEL_PACKAGE); + + //add a single node to the graph, a programmer. + framedGraph.addFramedVertex(Programmer.class); + + //make sure the newly added node is actually a programmer + final Person programmer = framedGraph.traverse(input -> framedGraph.getTypeResolver().hasType(input.V(), Programmer.class)).next(Person.class); + Assert.assertTrue(programmer instanceof Programmer); + + //change the type resolution to person + programmer.setTypeResolution(Person.class); + + //make sure the newly added node is not actually a programmer + final Person person = framedGraph.traverse(input -> input.V()).next(Person.class); + Assert.assertFalse(person instanceof Programmer); + } + + + @Test + public void testHasTypeParentFromPackageRecursively() { + final Graph godGraph = TinkerGraph.open(); + final FramedGraph framedGraph = new DelegatingFramedGraph(godGraph, TEST_MODEL_PACKAGE); + + //add a single node to the graph, a programmer. + framedGraph.addFramedVertex(GodExtended.class); + + //make sure the newly added node is actually a programmer + final God god = framedGraph.traverse(input -> framedGraph.getTypeResolver().hasType(input.V(), God.class)).next(God.class); + Assert.assertTrue(god instanceof GodExtended); + + //change the type resolution to person + god.setTypeResolution(God.class); + + //make sure the newly added node is not actually a programmer + final Person godAgain = framedGraph.traverse(input -> input.V()).next(Person.class); + Assert.assertFalse(godAgain instanceof GodExtended); + } @Test public void testCustomTypeKey() { diff --git a/src/test/java/com/syncleus/ferma/Programmer.java b/src/test/java/com/syncleus/ferma/Programmer.java index efeecd0996cf728763f551f9c9424113d76457ea..98486c691b1353c141ce39acd3461534c5a91edf 100644 --- a/src/test/java/com/syncleus/ferma/Programmer.java +++ b/src/test/java/com/syncleus/ferma/Programmer.java @@ -15,6 +15,9 @@ */ package com.syncleus.ferma; +import com.syncleus.ferma.annotations.GraphElement; + +@GraphElement public class Programmer extends Person { static final ClassInitializer<Programmer> DEFAULT_INITIALIZER = new DefaultClassInitializer(Programmer.class); } diff --git a/src/test/java/com/syncleus/ferma/annotations/AdjacencyMethodHandlerTest.java b/src/test/java/com/syncleus/ferma/annotations/AdjacencyMethodHandlerTest.java index 32545ac391edd6b4745320d665b0188301ddbc30..e3c1d44f5fb354f7530340c9067e51ef4239d84b 100644 --- a/src/test/java/com/syncleus/ferma/annotations/AdjacencyMethodHandlerTest.java +++ b/src/test/java/com/syncleus/ferma/annotations/AdjacencyMethodHandlerTest.java @@ -30,6 +30,7 @@ import java.util.*; public class AdjacencyMethodHandlerTest { private static final Set<Class<?>> TEST_TYPES = new HashSet<>(Arrays.asList(new Class<?>[]{God.class, FatherEdge.class, GodExtended.class, GodAlternative.class})); + private static final String TEST_MODEL_PACKAGE = "com.syncleus.ferma"; @Test public void testGetSonsDefault() { diff --git a/src/test/java/com/syncleus/ferma/annotations/God.java b/src/test/java/com/syncleus/ferma/annotations/God.java index 42fcaf22d7e6ed30209f058633db58c384ddbfd9..e783f9a63816c987ce5cb334b0ab43f64668bba0 100644 --- a/src/test/java/com/syncleus/ferma/annotations/God.java +++ b/src/test/java/com/syncleus/ferma/annotations/God.java @@ -20,6 +20,7 @@ import org.apache.tinkerpop.gremlin.structure.Direction; import java.util.Iterator; +@GraphElement public interface God extends VertexFrame { static final ClassInitializer<God> DEFAULT_INITIALIZER = new DefaultClassInitializer(God.class); diff --git a/src/test/java/com/syncleus/ferma/annotations/GodExtended.java b/src/test/java/com/syncleus/ferma/annotations/GodExtended.java index 9f14bbe0f4409a7cd142c30edb384a93f0b828e5..dfb497fc05683b7adacb9a432b4320d6fcf13fa0 100644 --- a/src/test/java/com/syncleus/ferma/annotations/GodExtended.java +++ b/src/test/java/com/syncleus/ferma/annotations/GodExtended.java @@ -18,6 +18,7 @@ package com.syncleus.ferma.annotations; import com.syncleus.ferma.ClassInitializer; import com.syncleus.ferma.DefaultClassInitializer; +@GraphElement public interface GodExtended extends GodIntermediate { static final ClassInitializer<GodExtended> DEFAULT_INITIALIZER = new DefaultClassInitializer(GodExtended.class); diff --git a/src/test/java/com/syncleus/ferma/annotations/GodIntermediate.java b/src/test/java/com/syncleus/ferma/annotations/GodIntermediate.java index 04ce2289259d7418cfcfb5cc0e1c5bfa7c256c99..9e6a49f5c161b7ff4d503af7b3d9be1680775583 100644 --- a/src/test/java/com/syncleus/ferma/annotations/GodIntermediate.java +++ b/src/test/java/com/syncleus/ferma/annotations/GodIntermediate.java @@ -18,6 +18,7 @@ package com.syncleus.ferma.annotations; import com.syncleus.ferma.ClassInitializer; import com.syncleus.ferma.DefaultClassInitializer; +@GraphElement public interface GodIntermediate extends God { static final ClassInitializer<GodIntermediate> DEFAULT_INITIALIZER = new DefaultClassInitializer(GodIntermediate.class); }