From 4f8ae9c83ddeab8fd8710a3755979872ed827ace Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Freeman <jeffrey.freeman@syncleus.com> Date: Thu, 21 Sep 2017 22:55:42 -0400 Subject: [PATCH] feat: can now specify a pacage to scan instead of explicit classes. --- CHANGELOG.md | 3 +- pom.xml | 2 +- .../syncleus/ferma/DelegatingFramedGraph.java | 20 +++--- .../com/syncleus/ferma/ReflectionCache.java | 7 ++ src/test/java/com/syncleus/ferma/Person.java | 2 + .../ferma/PolymorphicTypeResolverTest.java | 65 +++++++++++++++++++ .../java/com/syncleus/ferma/Programmer.java | 3 + .../AdjacencyMethodHandlerTest.java | 1 + .../com/syncleus/ferma/annotations/God.java | 1 + .../ferma/annotations/GodExtended.java | 1 + .../ferma/annotations/GodIntermediate.java | 1 + 11 files changed, 96 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cee5412f..60b3727b 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 805dc805..724621bc 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 8a12aec5..1a2d5f59 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 8e640c88..3d2c735a 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 108cbf9b..68589e24 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 dd671de4..5b9f2421 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 efeecd09..98486c69 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 32545ac3..e3c1d44f 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 42fcaf22..e783f9a6 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 9f14bbe0..dfb497fc 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 04ce2289..9e6a49f5 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); } -- GitLab