diff --git a/community/pom.xml b/community/pom.xml
index e3f0ec0099e6e..a7834b97c4bf5 100644
--- a/community/pom.xml
+++ b/community/pom.xml
@@ -65,6 +65,7 @@
licensecheck-config
dbms
command-line
+ procedure-compiler
diff --git a/community/procedure-compiler/README.md b/community/procedure-compiler/README.md
new file mode 100644
index 0000000000000..4a2a8b706fd10
--- /dev/null
+++ b/community/procedure-compiler/README.md
@@ -0,0 +1,28 @@
+# Neo4j Tooling - Procedure|User Function Compiler
+
+This is a annotation processor that will verify your stored procedures
+at compile time.
+
+While most of the basic checks can be performed, you still need
+some unit tests to verify some runtime behaviours.
+
+
+# What does it do?
+
+Once the stored procedure compiler is added into your project classpath (see Maven/Gradle
+instructions below), it will trigger compilation failures if any of the following requirements
+is not met:
+
+ - `@Context` fields must be `public` and non-`final`
+ - all other fields must be `static`
+ - `Map` record fields/procedure parameters must define their key type as `String`
+ - `@Procedure` class must define a public constructor with no arguments
+ - `@Procedure` method must return a Stream
+ - `@Procedure` parameter and record types must be supported
+ - `@Procedure` parameters must be annotated with `@Name`
+ - all visited `@Procedure` names must be unique*
+
+*A deployed Neo4j instance can aggregate stored procedures from different JARs.
+Inter-JAR naming conflict cannot be detected by an annotation processor.
+By definition, it can only inspect one compilation unit at a time.
+
diff --git a/community/procedure-compiler/integration-tests/pom.xml b/community/procedure-compiler/integration-tests/pom.xml
new file mode 100644
index 0000000000000..3b22f2c246b73
--- /dev/null
+++ b/community/procedure-compiler/integration-tests/pom.xml
@@ -0,0 +1,100 @@
+
+ 4.0.0
+
+
+
+ org.neo4j
+ procedure-compiler-parent
+ 3.1.0-SNAPSHOT
+ ..
+
+
+ procedure-compiler-integration-tests
+ jar
+
+ Neo4j - Procedure Compiler Integration Tests
+
+
+
+ org.neo4j
+ procedure-compiler
+ ${project.version}
+ compile
+ true
+
+
+ org.neo4j
+ procedure-compiler
+ ${project.version}
+ test
+ test-jar
+ tests
+
+
+ org.neo4j
+ neo4j
+ ${project.version}
+ test
+
+
+ org.neo4j.test
+ neo4j-harness
+ ${project.version}
+ test
+
+
+ org.neo4j.driver
+ neo4j-java-driver
+ 1.0.3
+ test
+
+
+ junit
+ junit
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+
+
+
+
+ maven-jar-plugin
+
+
+ default-jar
+ none
+
+
+
+
+ maven-install-plugin
+
+
+ default-install
+ none
+
+
+
+
+ maven-gpg-plugin
+
+
+ sign-artifacts
+ none
+
+
+
+
+ maven-deploy-plugin
+
+ true
+
+
+
+
+
diff --git a/community/procedure-compiler/integration-tests/src/test/java/org/neo4j/tooling/procedure/ProcedureTest.java b/community/procedure-compiler/integration-tests/src/test/java/org/neo4j/tooling/procedure/ProcedureTest.java
new file mode 100644
index 0000000000000..c8d13e8638f69
--- /dev/null
+++ b/community/procedure-compiler/integration-tests/src/test/java/org/neo4j/tooling/procedure/ProcedureTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure;
+
+import org.neo4j.tooling.procedure.procedures.valid.Procedures;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.neo4j.driver.v1.Config;
+import org.neo4j.driver.v1.Driver;
+import org.neo4j.driver.v1.GraphDatabase;
+import org.neo4j.driver.v1.Session;
+import org.neo4j.driver.v1.StatementResult;
+import org.neo4j.harness.junit.Neo4jRule;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+
+public class ProcedureTest
+{
+
+ private static final Class> PROCEDURES_CLASS = Procedures.class;
+
+ @Rule
+ public Neo4jRule graphDb = new Neo4jRule().withProcedure( PROCEDURES_CLASS );
+ private String procedureNamespace = PROCEDURES_CLASS.getPackage().getName();
+
+ @Test
+ public void calls_simplistic_procedure()
+ {
+ try ( Driver driver = GraphDatabase.driver( graphDb.boltURI(), configuration() );
+ Session session = driver.session() )
+ {
+
+ StatementResult result = session.run( "CALL " + procedureNamespace + ".theAnswer()" );
+
+ assertThat( result.single().get( "value" ).asLong() ).isEqualTo( 42L );
+ }
+ }
+
+ @Test
+ public void calls_procedures_with_simple_input_type_returning_void()
+ {
+ try ( Driver driver = GraphDatabase.driver( graphDb.boltURI(), configuration() );
+ Session session = driver.session() )
+ {
+
+ session.run( "CALL " + procedureNamespace + ".simpleInput00()" );
+ session.run( "CALL " + procedureNamespace + ".simpleInput01('string')" );
+ session.run( "CALL " + procedureNamespace + ".simpleInput02(42)" );
+ session.run( "CALL " + procedureNamespace + ".simpleInput03(42)" );
+ session.run( "CALL " + procedureNamespace + ".simpleInput04(4.2)" );
+ session.run( "CALL " + procedureNamespace + ".simpleInput05(true)" );
+ session.run( "CALL " + procedureNamespace + ".simpleInput06(false)" );
+ session.run( "CALL " + procedureNamespace + ".simpleInput07({foo:'bar'})" );
+ session.run( "MATCH (n) CALL " + procedureNamespace + ".simpleInput08(n) RETURN n" );
+ session.run( "MATCH p=(()-[r]->()) CALL " + procedureNamespace + ".simpleInput09(p) RETURN p" );
+ session.run( "MATCH ()-[r]->() CALL " + procedureNamespace + ".simpleInput10(r) RETURN r" );
+ }
+ }
+
+ @Test
+ public void calls_procedures_with_simple_input_type_returning_record_with_primitive_fields()
+ {
+ try ( Driver driver = GraphDatabase.driver( graphDb.boltURI(), configuration() );
+ Session session = driver.session() )
+ {
+
+ assertThat( session.run( "CALL " + procedureNamespace + ".simpleInput11('string')" ).single() ).isNotNull();
+ assertThat( session.run( "CALL " + procedureNamespace + ".simpleInput12(42)" ).single() ).isNotNull();
+ assertThat( session.run( "CALL " + procedureNamespace + ".simpleInput13(42)" ).single() ).isNotNull();
+ assertThat( session.run( "CALL " + procedureNamespace + ".simpleInput14(4.2)" ).single() ).isNotNull();
+ assertThat( session.run( "CALL " + procedureNamespace + ".simpleInput15(true)" ).single() ).isNotNull();
+ assertThat( session.run( "CALL " + procedureNamespace + ".simpleInput16(false)" ).single() ).isNotNull();
+ assertThat( session.run( "CALL " + procedureNamespace + ".simpleInput17({foo:'bar'})" ).single() )
+ .isNotNull();
+ assertThat( session.run( "CALL " + procedureNamespace + ".simpleInput21()" ).single() ).isNotNull();
+ }
+
+ }
+
+ private Config configuration()
+ {
+ return Config.build().withEncryptionLevel( Config.EncryptionLevel.NONE ).toConfig();
+ }
+
+}
diff --git a/community/procedure-compiler/pom.xml b/community/procedure-compiler/pom.xml
new file mode 100644
index 0000000000000..ae3e600ba6ba6
--- /dev/null
+++ b/community/procedure-compiler/pom.xml
@@ -0,0 +1,73 @@
+
+
+ org.neo4j
+ parent
+ 3.1.0-SNAPSHOT
+ ../..
+
+
+
+ procedure-compiler
+ org.neo4j.tooling.procedure
+ GPL-3-header.txt
+ notice-gpl-prefix.txt
+ tooling.procedure
+
+
+ 4.0.0
+ procedure-compiler-parent
+ 3.1.0-SNAPSHOT
+ pom
+
+ Neo4j - Procedure Compiler Parent POM
+ Neo4j Stored Procedure compile-time annotation processor
+ http://components.neo4j.org/${project.artifactId}/${project.version}
+
+
+ scm:git:git://github.com/neo4j/neo4j.git
+ scm:git:git@github.com:neo4j/neo4j.git
+ https://github.com/neo4j/neo4j
+
+
+
+
+ GNU General Public License, Version 3
+ http://www.gnu.org/licenses/gpl-3.0-standalone.html
+ The software ("Software") developed and owned by Network Engine for
+ Objects in Lund AB (referred to in this notice as "Neo Technology") is
+ licensed under the GNU GENERAL PUBLIC LICENSE Version 3 to all third
+ parties and that license is included below.
+
+ However, if you have executed an End User Software License and Services
+ Agreement or an OEM Software License and Support Services Agreement, or
+ another commercial license agreement with Neo Technology or one of its
+ affiliates (each, a "Commercial Agreement"), the terms of the license in
+ such Commercial Agreement will supersede the GNU GENERAL PUBLIC LICENSE
+ Version 3 and you may use the Software solely pursuant to the terms of
+ the relevant Commercial Agreement.
+
+
+
+
+
+ processor
+ integration-tests
+
+
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ org.assertj
+ assertj-core
+ 3.4.1
+ test
+
+
+
+
diff --git a/community/procedure-compiler/processor/LICENSES.txt b/community/procedure-compiler/processor/LICENSES.txt
new file mode 100644
index 0000000000000..35e8354a7c7d9
--- /dev/null
+++ b/community/procedure-compiler/processor/LICENSES.txt
@@ -0,0 +1,214 @@
+This file contains the full license text of the included third party
+libraries. For an overview of the licenses see the NOTICE.txt file.
+
+------------------------------------------------------------------------------
+Apache Software License, Version 2.0
+ Auto Common Libraries
+ AutoService
+ Guava: Google Core Libraries for Java
+------------------------------------------------------------------------------
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+
diff --git a/community/procedure-compiler/processor/NOTICE.txt b/community/procedure-compiler/processor/NOTICE.txt
new file mode 100644
index 0000000000000..5a712a368d0e9
--- /dev/null
+++ b/community/procedure-compiler/processor/NOTICE.txt
@@ -0,0 +1,32 @@
+Neo4j
+Copyright © 2002-2016 Network Engine for Objects in Lund AB (referred to
+in this notice as "Neo Technology")
+ [http://neotechnology.com]
+
+This product includes software ("Software") developed by Neo Technology.
+
+The copyright in the bundled Neo4j graph database (including the
+Software) is owned by Neo Technology. The Software developed and owned
+by Neo Technology is licensed under the GNU GENERAL PUBLIC LICENSE
+Version 3 (http://www.fsf.org/licensing/licenses/gpl-3.0.html) ("GPL")
+to all third parties and that license, as required by the GPL, is
+included in the LICENSE.txt file.
+
+However, if you have executed an End User Software License and Services
+Agreement or an OEM Software License and Support Services Agreement, or
+another commercial license agreement with Neo Technology or one of its
+affiliates (each, a "Commercial Agreement"), the terms of the license in
+such Commercial Agreement will supersede the GPL and you may use the
+software solely pursuant to the terms of the relevant Commercial
+Agreement.
+
+Full license texts are found in LICENSES.txt.
+
+Third-party licenses
+--------------------
+
+Apache Software License, Version 2.0
+ Auto Common Libraries
+ AutoService
+ Guava: Google Core Libraries for Java
+
diff --git a/community/procedure-compiler/processor/pom.xml b/community/procedure-compiler/processor/pom.xml
new file mode 100644
index 0000000000000..b0a3a01cc012c
--- /dev/null
+++ b/community/procedure-compiler/processor/pom.xml
@@ -0,0 +1,89 @@
+
+ 4.0.0
+
+
+ org.neo4j
+ procedure-compiler-parent
+ 3.1.0-SNAPSHOT
+ ..
+
+
+ procedure-compiler
+ jar
+
+ Neo4j - Procedure Compiler Core
+
+
+
+ org.neo4j
+ neo4j
+ ${project.version}
+ provided
+
+
+ com.google.auto.service
+ auto-service
+ 1.0-rc2
+ true
+
+
+ junit
+ junit
+ test
+
+
+ com.google.testing.compile
+ compile-testing
+ 0.9
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+
+
+
+
+ src/test/resources
+ true
+
+
+
+
+ maven-source-plugin
+
+
+ maven-javadoc-plugin
+
+
+ maven-compiler-plugin
+
+
+ com.google.auto.service.processor.AutoServiceProcessor
+
+
+
+
+
+ maven-jar-plugin
+ 3.0.1
+
+
+
+ test-jar
+
+
+
+ org/neo4j/tooling/procedure/procedures/valid/**/*
+
+
+
+
+
+
+
+
+
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/PerformsWriteProcessor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/PerformsWriteProcessor.java
new file mode 100644
index 0000000000000..70f1677c7bf1c
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/PerformsWriteProcessor.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure;
+
+import com.google.auto.service.AutoService;
+import org.neo4j.tooling.procedure.messages.CompilationMessage;
+import org.neo4j.tooling.procedure.messages.MessagePrinter;
+import org.neo4j.tooling.procedure.visitors.PerformsWriteMethodVisitor;
+
+import java.lang.annotation.Annotation;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Stream;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.TypeElement;
+
+import org.neo4j.procedure.PerformsWrites;
+
+@AutoService( Processor.class )
+public class PerformsWriteProcessor extends AbstractProcessor
+{
+ private static final Class extends Annotation> performWritesType = PerformsWrites.class;
+ private MessagePrinter messagePrinter;
+ private ElementVisitor,Void> visitor;
+
+ @Override
+ public Set getSupportedAnnotationTypes()
+ {
+ Set types = new HashSet<>();
+ types.add( performWritesType.getName() );
+ return types;
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion()
+ {
+ return SourceVersion.RELEASE_8;
+ }
+
+ @Override
+ public synchronized void init( ProcessingEnvironment processingEnv )
+ {
+ super.init( processingEnv );
+ messagePrinter = new MessagePrinter( processingEnv.getMessager() );
+ visitor = new PerformsWriteMethodVisitor();
+ }
+
+ @Override
+ public boolean process( Set extends TypeElement> annotations, RoundEnvironment roundEnv )
+ {
+ processPerformsWriteElements( roundEnv );
+ return false;
+ }
+
+ private void processPerformsWriteElements( RoundEnvironment roundEnv )
+ {
+ roundEnv.getElementsAnnotatedWith( performWritesType ).stream().flatMap( this::validate )
+ .forEachOrdered( messagePrinter::print );
+
+ }
+
+ private Stream validate( Element element )
+ {
+ return visitor.visit( element );
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/ProcedureProcessor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/ProcedureProcessor.java
new file mode 100644
index 0000000000000..7c56b904370da
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/ProcedureProcessor.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure;
+
+import com.google.auto.service.AutoService;
+import org.neo4j.tooling.procedure.messages.CompilationMessage;
+import org.neo4j.tooling.procedure.messages.MessagePrinter;
+import org.neo4j.tooling.procedure.validators.DuplicatedProcedureValidator;
+import org.neo4j.tooling.procedure.visitors.StoredProcedureVisitor;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import org.neo4j.procedure.Procedure;
+
+@AutoService( Processor.class )
+public class ProcedureProcessor extends AbstractProcessor
+{
+
+ private static final Class sprocType = Procedure.class;
+ private static final String IGNORE_CONTEXT_WARNINGS = "IgnoreContextWarnings";
+ private final Set visitedProcedures = new LinkedHashSet<>();
+
+ private Function,Stream> duplicationPredicate;
+ private ElementVisitor,Void> visitor;
+ private MessagePrinter messagePrinter;
+
+ public static Optional getCustomName( Procedure proc )
+ {
+ String name = proc.name();
+ if ( !name.isEmpty() )
+ {
+ return Optional.of( name );
+ }
+ String value = proc.value();
+ if ( !value.isEmpty() )
+ {
+ return Optional.of( value );
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public Set getSupportedOptions()
+ {
+ return Collections.singleton( IGNORE_CONTEXT_WARNINGS );
+ }
+
+ @Override
+ public Set getSupportedAnnotationTypes()
+ {
+ Set types = new HashSet<>();
+ types.add( sprocType.getName() );
+ return types;
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion()
+ {
+ return SourceVersion.RELEASE_8;
+ }
+
+ @Override
+ public synchronized void init( ProcessingEnvironment processingEnv )
+ {
+ super.init( processingEnv );
+ Types typeUtils = processingEnv.getTypeUtils();
+ Elements elementUtils = processingEnv.getElementUtils();
+
+ visitedProcedures.clear();
+ messagePrinter = new MessagePrinter( processingEnv.getMessager() );
+ visitor = new StoredProcedureVisitor( typeUtils, elementUtils, processingEnv.getOptions().containsKey(
+ IGNORE_CONTEXT_WARNINGS) );
+ duplicationPredicate =
+ new DuplicatedProcedureValidator<>( elementUtils, sprocType, ProcedureProcessor::getCustomName );
+ }
+
+ @Override
+ public boolean process( Set extends TypeElement> annotations, RoundEnvironment roundEnv )
+ {
+
+ processElements( roundEnv );
+ if ( roundEnv.processingOver() )
+ {
+ duplicationPredicate.apply( visitedProcedures ).forEach( messagePrinter::print );
+ }
+ return false;
+ }
+
+ private void processElements( RoundEnvironment roundEnv )
+ {
+ Set extends Element> procedures = roundEnv.getElementsAnnotatedWith( sprocType );
+ visitedProcedures.addAll( procedures );
+ procedures.stream().flatMap( this::validate ).forEachOrdered( messagePrinter::print );
+ }
+
+ private Stream validate( Element element )
+ {
+ return visitor.visit( element );
+ }
+
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/UserFunctionProcessor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/UserFunctionProcessor.java
new file mode 100644
index 0000000000000..a15f4c507a56d
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/UserFunctionProcessor.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure;
+
+import com.google.auto.service.AutoService;
+import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils;
+import org.neo4j.tooling.procedure.messages.CompilationMessage;
+import org.neo4j.tooling.procedure.messages.MessagePrinter;
+import org.neo4j.tooling.procedure.validators.DuplicatedProcedureValidator;
+import org.neo4j.tooling.procedure.visitors.UserFunctionVisitor;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import org.neo4j.procedure.UserFunction;
+
+@AutoService( Processor.class )
+public class UserFunctionProcessor extends AbstractProcessor
+{
+ private static final Class userFunctionType = UserFunction.class;
+ private final Set visitedFunctions = new LinkedHashSet<>();
+
+ private ElementVisitor,Void> visitor;
+ private MessagePrinter messagePrinter;
+ private Function,Stream> duplicationPredicate;
+
+ public static Optional getCustomName( UserFunction function )
+ {
+ String name = function.name();
+ if ( !name.isEmpty() )
+ {
+ return Optional.of( name );
+ }
+ String value = function.value();
+ if ( !value.isEmpty() )
+ {
+ return Optional.of( value );
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public Set getSupportedAnnotationTypes()
+ {
+ Set types = new HashSet<>();
+ types.add( userFunctionType.getName() );
+ return types;
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion()
+ {
+ return SourceVersion.RELEASE_8;
+ }
+
+ @Override
+ public synchronized void init( ProcessingEnvironment processingEnv )
+ {
+ super.init( processingEnv );
+ Types typeUtils = processingEnv.getTypeUtils();
+ Elements elementUtils = processingEnv.getElementUtils();
+
+ visitedFunctions.clear();
+ messagePrinter = new MessagePrinter( processingEnv.getMessager() );
+ visitor = new UserFunctionVisitor( typeUtils, elementUtils, new TypeMirrorUtils( typeUtils, elementUtils ) );
+ duplicationPredicate = new DuplicatedProcedureValidator<>( elementUtils, userFunctionType,
+ UserFunctionProcessor::getCustomName );
+ }
+
+ @Override
+ public boolean process( Set extends TypeElement> annotations, RoundEnvironment roundEnv )
+ {
+ processElements( roundEnv );
+ if ( roundEnv.processingOver() )
+ {
+ duplicationPredicate.apply( visitedFunctions ).forEach( messagePrinter::print );
+ }
+ return false;
+ }
+
+ private void processElements( RoundEnvironment roundEnv )
+ {
+ Set extends Element> functions = roundEnv.getElementsAnnotatedWith( userFunctionType );
+ visitedFunctions.addAll( functions );
+ functions.stream().flatMap( this::validate ).forEachOrdered( messagePrinter::print );
+ }
+
+ private Stream validate( Element element )
+ {
+ return visitor.visit( element );
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/compilerutils/TypeMirrorUtils.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/compilerutils/TypeMirrorUtils.java
new file mode 100644
index 0000000000000..282671efc4c03
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/compilerutils/TypeMirrorUtils.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.compilerutils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Path;
+import org.neo4j.graphdb.Relationship;
+
+import static java.util.Arrays.asList;
+
+public class TypeMirrorUtils
+{
+
+ private Types typeUtils;
+ private Elements elementUtils;
+
+ public TypeMirrorUtils( Types typeUtils, Elements elementUtils )
+ {
+ this.typeUtils = typeUtils;
+ this.elementUtils = elementUtils;
+ }
+
+ public final Collection procedureAllowedTypes()
+ {
+ PrimitiveType bool = primitive( TypeKind.BOOLEAN );
+ PrimitiveType longType = primitive( TypeKind.LONG );
+ PrimitiveType doubleType = primitive( TypeKind.DOUBLE );
+ return asList( bool, boxed( bool ), longType, boxed( longType ), doubleType, boxed( doubleType ),
+ typeMirror( String.class ), typeMirror( Number.class ), typeMirror( Object.class ),
+ typeMirror( Map.class ), typeMirror( List.class ), typeMirror( Node.class ),
+ typeMirror( Relationship.class ), typeMirror( Path.class ) );
+ }
+
+ public PrimitiveType primitive( TypeKind kind )
+ {
+ return typeUtils.getPrimitiveType( kind );
+ }
+
+ public TypeMirror typeMirror( Class> type )
+ {
+ return elementUtils.getTypeElement( type.getName() ).asType();
+ }
+
+ private TypeMirror boxed( PrimitiveType bool )
+ {
+ return typeUtils.boxedClass( bool ).asType();
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/CompilationMessage.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/CompilationMessage.java
new file mode 100644
index 0000000000000..99c792cd64002
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/CompilationMessage.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.messages;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.tools.Diagnostic;
+
+public interface CompilationMessage
+{
+ Element getElement();
+
+ String getContents();
+
+ default AnnotationMirror getMirror()
+ {
+ return null;
+ }
+
+ default Diagnostic.Kind getCategory()
+ {
+ return Diagnostic.Kind.ERROR;
+ }
+}
+
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ContextFieldWarning.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ContextFieldWarning.java
new file mode 100644
index 0000000000000..a2250366a23a4
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ContextFieldWarning.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.messages;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.VariableElement;
+import javax.tools.Diagnostic;
+
+public class ContextFieldWarning implements CompilationMessage
+{
+ private final Element element;
+ private final String contents;
+
+ public ContextFieldWarning( VariableElement element, String message, Object... args )
+ {
+ this.element = element;
+ this.contents = String.format( message, args );
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+
+ @Override
+ public String getContents()
+ {
+ return contents;
+ }
+
+ @Override
+ public Diagnostic.Kind getCategory()
+ {
+ return Diagnostic.Kind.WARNING;
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/DuplicatedProcedureError.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/DuplicatedProcedureError.java
new file mode 100644
index 0000000000000..51394d0b654d1
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/DuplicatedProcedureError.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.messages;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+
+public class DuplicatedProcedureError implements CompilationMessage
+{
+
+ private final Element element;
+ private final AnnotationMirror annotationMirror;
+ private final String errorMessage;
+
+ public DuplicatedProcedureError( Element element, AnnotationMirror annotationMirror, String errorMessage,
+ Object... args )
+ {
+ this.element = element;
+ this.annotationMirror = annotationMirror;
+ this.errorMessage = String.format( errorMessage, args );
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+
+ @Override
+ public AnnotationMirror getMirror()
+ {
+ return annotationMirror;
+ }
+
+ @Override
+ public String getContents()
+ {
+ return errorMessage;
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/FieldError.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/FieldError.java
new file mode 100644
index 0000000000000..49cb8607690c0
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/FieldError.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.messages;
+
+import javax.lang.model.element.VariableElement;
+
+public class FieldError implements CompilationMessage
+{
+
+ private final VariableElement field;
+ private final String errorMessage;
+
+ public FieldError( VariableElement field, String errorMessage, Object... args )
+ {
+
+ this.field = field;
+ this.errorMessage = String.format( errorMessage, args );
+ }
+
+ @Override
+ public VariableElement getElement()
+ {
+ return field;
+ }
+
+ @Override
+ public String getContents()
+ {
+ return errorMessage;
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/FunctionInRootNamespaceError.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/FunctionInRootNamespaceError.java
new file mode 100644
index 0000000000000..fcf58c8da36fe
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/FunctionInRootNamespaceError.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.messages;
+
+import javax.lang.model.element.Element;
+
+public class FunctionInRootNamespaceError implements CompilationMessage
+{
+ private final Element element;
+ private final String contents;
+
+ public FunctionInRootNamespaceError( Element element, String message, Object... args )
+ {
+ this.element = element;
+ this.contents = String.format( message, args );
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+
+ @Override
+ public String getContents()
+ {
+ return contents;
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/MessagePrinter.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/MessagePrinter.java
new file mode 100644
index 0000000000000..1ba1f79a323cd
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/MessagePrinter.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.messages;
+
+import javax.annotation.processing.Messager;
+
+public class MessagePrinter
+{
+
+ private final Messager messager;
+
+ public MessagePrinter( Messager messager )
+ {
+ this.messager = messager;
+ }
+
+ public void print( CompilationMessage message )
+ {
+ messager.printMessage( message.getCategory(), message.getContents(), message.getElement(),
+ message.getMirror() );
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ParameterMissingAnnotationError.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ParameterMissingAnnotationError.java
new file mode 100644
index 0000000000000..035abb1cb9034
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ParameterMissingAnnotationError.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.messages;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+
+public class ParameterMissingAnnotationError implements CompilationMessage
+{
+ private final Element element;
+ private final AnnotationMirror mirror;
+ private final String errorMessage;
+
+ public ParameterMissingAnnotationError( Element element, AnnotationMirror mirror, String errorMessage,
+ Object... args )
+ {
+ this.element = element;
+ this.mirror = mirror;
+ this.errorMessage = String.format( errorMessage, args );
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+
+ @Override
+ public AnnotationMirror getMirror()
+ {
+ return mirror;
+ }
+
+ @Override
+ public String getContents()
+ {
+ return errorMessage;
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ParameterTypeError.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ParameterTypeError.java
new file mode 100644
index 0000000000000..345397bb8cdc2
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ParameterTypeError.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.messages;
+
+import javax.lang.model.element.Element;
+
+public class ParameterTypeError implements CompilationMessage
+{
+
+ private final Element element;
+ private final String errorMessage;
+
+ public ParameterTypeError( Element element, String errorMessage, Object... args )
+ {
+ this.element = element;
+ this.errorMessage = String.format( errorMessage, args );
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+
+ @Override
+ public String getContents()
+ {
+ return errorMessage;
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/PerformsWriteMisuseError.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/PerformsWriteMisuseError.java
new file mode 100644
index 0000000000000..c0ae30de9675b
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/PerformsWriteMisuseError.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.messages;
+
+import javax.lang.model.element.Element;
+
+public class PerformsWriteMisuseError implements CompilationMessage
+{
+ private final Element method;
+ private final String errorMessage;
+
+ public PerformsWriteMisuseError( Element method, String message, Object... args )
+ {
+
+ this.method = method;
+ this.errorMessage = String.format( message, args );
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return method;
+ }
+
+ @Override
+ public String getContents()
+ {
+ return errorMessage;
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ProcedureMissingPublicNoArgConstructor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ProcedureMissingPublicNoArgConstructor.java
new file mode 100644
index 0000000000000..6cfb7f6ab2d46
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ProcedureMissingPublicNoArgConstructor.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.messages;
+
+import javax.lang.model.element.Element;
+
+public class ProcedureMissingPublicNoArgConstructor implements CompilationMessage
+{
+
+ private final Element element;
+ private final String errorMessage;
+
+ public ProcedureMissingPublicNoArgConstructor( Element element, String message, Object... args )
+ {
+
+ this.element = element;
+ this.errorMessage = String.format( message, args );
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+
+ @Override
+ public String getContents()
+ {
+ return errorMessage;
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/RecordTypeError.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/RecordTypeError.java
new file mode 100644
index 0000000000000..2e8faf428ea34
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/RecordTypeError.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.messages;
+
+import javax.lang.model.element.Element;
+
+public class RecordTypeError implements CompilationMessage
+{
+
+ private final Element element;
+ private final String errorMessage;
+
+ public RecordTypeError( Element element, String errorMessage, Object... args )
+ {
+ this.element = element;
+ this.errorMessage = String.format( errorMessage, args );
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+
+ @Override
+ public String getContents()
+ {
+ return errorMessage;
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ReturnTypeError.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ReturnTypeError.java
new file mode 100644
index 0000000000000..5366d6ea43bca
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/messages/ReturnTypeError.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.messages;
+
+import javax.lang.model.element.Element;
+
+public class ReturnTypeError implements CompilationMessage
+{
+
+ private final Element element;
+ private final String errorMessage;
+
+ public ReturnTypeError( Element element, String errorMessage, Object... args )
+ {
+ this.element = element;
+ this.errorMessage = String.format( errorMessage, args );
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+
+ @Override
+ public String getContents()
+ {
+ return errorMessage;
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/validators/AllowedTypesValidator.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/validators/AllowedTypesValidator.java
new file mode 100644
index 0000000000000..d878227d46a16
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/validators/AllowedTypesValidator.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.validators;
+
+import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor8;
+import javax.lang.model.util.Types;
+
+/**
+ * This predicate makes sure that a given declared type (record field type,
+ * procedure parameter type...) is supported by Neo4j stored procedures.
+ */
+public class AllowedTypesValidator implements Predicate
+{
+
+ private final TypeMirrorUtils typeMirrors;
+ private final Collection whitelistedTypes;
+ private final Types typeUtils;
+
+ public AllowedTypesValidator( TypeMirrorUtils typeMirrors, Types typeUtils )
+ {
+
+ this.typeMirrors = typeMirrors;
+ this.whitelistedTypes = typeMirrors.procedureAllowedTypes();
+ this.typeUtils = typeUtils;
+ }
+
+ @Override
+ public boolean test( TypeMirror typeMirror )
+ {
+ TypeMirror erasedActualType = typeUtils.erasure( typeMirror );
+
+ return isValidErasedType( erasedActualType ) &&
+ (!isSameErasedType( List.class, typeMirror ) || isValidListType( typeMirror )) &&
+ (!isSameErasedType( Map.class, typeMirror ) || isValidMapType( typeMirror ));
+ }
+
+ private boolean isValidErasedType( TypeMirror actualType )
+ {
+ return whitelistedTypes.stream().anyMatch( type ->
+ {
+ TypeMirror erasedAllowedType = typeUtils.erasure( type );
+
+ TypeMirror map = typeUtils.erasure( typeMirrors.typeMirror( Map.class ) );
+ TypeMirror list = typeUtils.erasure( typeMirrors.typeMirror( List.class ) );
+ if ( typeUtils.isSameType( erasedAllowedType, map ) || typeUtils.isSameType( erasedAllowedType, list ) )
+ {
+ return typeUtils.isSubtype( actualType, erasedAllowedType );
+ }
+
+ return typeUtils.isSameType( actualType, erasedAllowedType );
+ } );
+ }
+
+ /**
+ * Recursively visits List type arguments
+ *
+ * @param typeMirror the List type mirror
+ * @return true if the declaration is valid, false otherwise
+ */
+ private boolean isValidListType( TypeMirror typeMirror )
+ {
+ return new SimpleTypeVisitor8()
+ {
+ @Override
+ public Boolean visitDeclared( DeclaredType list, Void aVoid )
+ {
+ List extends TypeMirror> typeArguments = list.getTypeArguments();
+ if ( typeArguments.size() != 1 )
+ {
+ return false;
+ }
+ return test( typeArguments.get( 0 ) );
+ }
+ }.visit( typeMirror );
+ }
+
+ /**
+ * Recursively visits Map type arguments
+ * Map key type argument must be a String as of Neo4j stored procedure specification
+ * Map value type argument is recursively visited
+ *
+ * @param typeMirror Map type mirror
+ * @return true if the declaration is valid, false otherwise
+ */
+ private boolean isValidMapType( TypeMirror typeMirror )
+ {
+ return new SimpleTypeVisitor8()
+ {
+ @Override
+ public Boolean visitDeclared( DeclaredType map, Void ignored )
+ {
+ List extends TypeMirror> typeArguments = map.getTypeArguments();
+ if ( typeArguments.size() != 2 )
+ {
+ return false;
+ }
+
+ TypeMirror key = typeArguments.get( 0 );
+ if ( !typeUtils.isSameType( key, typeMirrors.typeMirror( String.class ) ) )
+ {
+ return false;
+ }
+ return test( typeArguments.get( 1 ) );
+ }
+ }.visit( typeMirror );
+ }
+
+ private boolean isSameErasedType( Class> type, TypeMirror typeMirror )
+ {
+ return typeUtils
+ .isSameType( typeUtils.erasure( typeMirrors.typeMirror( type ) ), typeUtils.erasure( typeMirror ) );
+ }
+
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/validators/DuplicatedProcedureValidator.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/validators/DuplicatedProcedureValidator.java
new file mode 100644
index 0000000000000..46c52c081d311
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/validators/DuplicatedProcedureValidator.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.validators;
+
+import org.neo4j.tooling.procedure.messages.CompilationMessage;
+import org.neo4j.tooling.procedure.messages.DuplicatedProcedureError;
+import org.neo4j.tooling.procedure.visitors.AnnotationTypeVisitor;
+
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.util.Elements;
+
+import org.neo4j.procedure.Procedure;
+
+import static java.util.stream.Collectors.groupingBy;
+
+public class DuplicatedProcedureValidator
+ implements Function,Stream>
+{
+
+ private final Elements elements;
+ private final Class annotationType;
+ private final Function> customNameExtractor;
+
+ public DuplicatedProcedureValidator( Elements elements, Class annotationType,
+ Function> customNameExtractor )
+ {
+ this.elements = elements;
+ this.annotationType = annotationType;
+ this.customNameExtractor = customNameExtractor;
+ }
+
+ @Override
+ public Stream apply( Collection visitedProcedures )
+ {
+ return findDuplicates( visitedProcedures );
+ }
+
+ private Stream findDuplicates( Collection visitedProcedures )
+ {
+ return indexByName( visitedProcedures ).filter( index -> index.getValue().size() > 1 )
+ .flatMap( this::asErrors );
+ }
+
+ private Stream>> indexByName( Collection visitedProcedures )
+ {
+ return visitedProcedures.stream().collect( groupingBy( this::getName ) ).entrySet().stream();
+ }
+
+ private String getName( Element procedure )
+ {
+ T annotation = procedure.getAnnotation( annotationType );
+ Optional customName = customNameExtractor.apply( annotation );
+ return customName.orElse( defaultQualifiedName( procedure ) );
+ }
+
+ private String defaultQualifiedName( Element procedure )
+ {
+ return String.format( "%s.%s", elements.getPackageOf( procedure ).toString(), procedure.getSimpleName() );
+ }
+
+ private Stream asErrors( Map.Entry> indexedProcedures )
+ {
+ String duplicatedName = indexedProcedures.getKey();
+ return indexedProcedures.getValue().stream()
+ .map( procedure -> asError( procedure, duplicatedName, indexedProcedures.getValue().size() ) );
+ }
+
+ private CompilationMessage asError( Element procedure, String duplicatedName, int duplicateCount )
+ {
+ return new DuplicatedProcedureError( procedure, getAnnotationMirror( procedure ),
+ "Procedure|function name <%s> is already defined %s times. It should be defined only once!",
+ duplicatedName, String.valueOf( duplicateCount ) );
+ }
+
+ private AnnotationMirror getAnnotationMirror( Element procedure )
+ {
+ return procedure.getAnnotationMirrors().stream().filter( this::isProcedureAnnotationType ).findFirst()
+ .orElse( null );
+ }
+
+ private boolean isProcedureAnnotationType( AnnotationMirror mirror )
+ {
+ return new AnnotationTypeVisitor( Procedure.class ).visit( mirror.getAnnotationType().asElement() );
+ }
+
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/AnnotationTypeVisitor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/AnnotationTypeVisitor.java
new file mode 100644
index 0000000000000..d5ef3b409ccda
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/AnnotationTypeVisitor.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.visitors;
+
+import java.lang.annotation.Annotation;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.SimpleElementVisitor8;
+
+public class AnnotationTypeVisitor extends SimpleElementVisitor8
+{
+
+ private final Class extends Annotation> annotationType;
+
+ public AnnotationTypeVisitor( Class extends Annotation> annotationType )
+ {
+ this.annotationType = annotationType;
+ }
+
+ @Override
+ public Boolean visitType( TypeElement element, Void aVoid )
+ {
+ return element.getQualifiedName().contentEquals( annotationType.getName() );
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/ContextFieldVisitor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/ContextFieldVisitor.java
new file mode 100644
index 0000000000000..a9bcd246dc71e
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/ContextFieldVisitor.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.visitors;
+
+import org.neo4j.tooling.procedure.messages.CompilationMessage;
+import org.neo4j.tooling.procedure.messages.ContextFieldWarning;
+import org.neo4j.tooling.procedure.messages.FieldError;
+
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleElementVisitor8;
+import javax.lang.model.util.Types;
+
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.logging.Log;
+import org.neo4j.procedure.Context;
+
+class ContextFieldVisitor extends SimpleElementVisitor8,Void>
+{
+ private static final Set> SUPPORTED_TYPES =
+ new LinkedHashSet<>( Arrays.asList( GraphDatabaseService.class, Log.class ) );
+
+ private final Elements elements;
+ private final Types types;
+ private final boolean skipContextWarnings;
+
+ public ContextFieldVisitor( Types types, Elements elements, boolean skipContextWarnings )
+ {
+ this.elements = elements;
+ this.types = types;
+ this.skipContextWarnings = skipContextWarnings;
+ }
+
+ private static String types( Set> supportedTypes )
+ {
+ return supportedTypes.stream().map( Class::getName ).collect( Collectors.joining( ">, <", "<", ">" ) );
+ }
+
+ @Override
+ public Stream visitVariable( VariableElement field, Void ignored )
+ {
+ return Stream.concat( validateModifiers( field ), validateInjectedTypes( field ) );
+ }
+
+ private Stream validateModifiers( VariableElement field )
+ {
+ if ( !hasValidModifiers( field ) )
+ {
+ return Stream.of( new FieldError( field,
+ "@%s usage error: field %s#%s should be public, non-static and non-final", Context.class.getName(),
+ field.getEnclosingElement().getSimpleName(), field.getSimpleName() ) );
+ }
+
+ return Stream.empty();
+ }
+
+ private Stream validateInjectedTypes( VariableElement field )
+ {
+ if ( skipContextWarnings )
+ {
+ return Stream.empty();
+ }
+
+ TypeMirror fieldType = field.asType();
+ if ( !injectsAllowedTypes( fieldType ) )
+ {
+ return Stream
+ .of( new ContextFieldWarning( field, "@%s usage warning: found type: <%s>, expected one of: %s",
+ Context.class.getName(), fieldType.toString(), types( SUPPORTED_TYPES ) ) );
+ }
+
+ return Stream.empty();
+ }
+
+ private boolean injectsAllowedTypes( TypeMirror fieldType )
+ {
+ return supportedTypeMirrors( SUPPORTED_TYPES ).filter( t -> types.isSameType( t, fieldType ) ).findAny()
+ .isPresent();
+ }
+
+ private boolean hasValidModifiers( VariableElement field )
+ {
+ Set modifiers = field.getModifiers();
+ return modifiers.contains( Modifier.PUBLIC ) && !modifiers.contains( Modifier.STATIC ) &&
+ !modifiers.contains( Modifier.FINAL );
+ }
+
+ private Stream supportedTypeMirrors( Set> supportedTypes )
+ {
+ return supportedTypes.stream().map( c -> elements.getTypeElement( c.getName() ).asType() );
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/FieldVisitor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/FieldVisitor.java
new file mode 100644
index 0000000000000..1ba633ee19cc0
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/FieldVisitor.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.visitors;
+
+import org.neo4j.tooling.procedure.messages.CompilationMessage;
+import org.neo4j.tooling.procedure.messages.FieldError;
+
+import java.util.Set;
+import java.util.stream.Stream;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleElementVisitor8;
+import javax.lang.model.util.Types;
+
+import org.neo4j.procedure.Context;
+
+public class FieldVisitor extends SimpleElementVisitor8,Void>
+{
+
+ private final ElementVisitor,Void> contextFieldVisitor;
+
+ public FieldVisitor( Types types, Elements elements, boolean skipContextWarnings )
+ {
+ contextFieldVisitor = new ContextFieldVisitor( types, elements, skipContextWarnings );
+ }
+
+ private static Stream validateNonContextField( VariableElement field )
+ {
+ Set modifiers = field.getModifiers();
+ if ( !modifiers.contains( Modifier.STATIC ) )
+ {
+ return Stream.of( new FieldError( field, "Field %s#%s should be static",
+ field.getEnclosingElement().getSimpleName(), field.getSimpleName() ) );
+ }
+ return Stream.empty();
+ }
+
+ @Override
+ public Stream visitVariable( VariableElement field, Void ignored )
+ {
+ if ( field.getAnnotation( Context.class ) != null )
+ {
+ return contextFieldVisitor.visitVariable( field, ignored );
+ }
+ return validateNonContextField( field );
+
+ }
+
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/ParameterTypeVisitor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/ParameterTypeVisitor.java
new file mode 100644
index 0000000000000..1e194b626e095
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/ParameterTypeVisitor.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.visitors;
+
+import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils;
+import org.neo4j.tooling.procedure.validators.AllowedTypesValidator;
+
+import java.util.function.Predicate;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor8;
+import javax.lang.model.util.Types;
+
+class ParameterTypeVisitor extends SimpleTypeVisitor8
+{
+
+ private final Predicate allowedTypesValidator;
+
+ public ParameterTypeVisitor( Types typeUtils, TypeMirrorUtils typeMirrors )
+ {
+ allowedTypesValidator = new AllowedTypesValidator( typeMirrors, typeUtils );
+ }
+
+ @Override
+ public Boolean visitDeclared( DeclaredType parameterType, Void ignored )
+ {
+ return validate( parameterType );
+ }
+
+ @Override
+ public Boolean visitPrimitive( PrimitiveType primitive, Void ignored )
+ {
+ return validate( primitive );
+ }
+
+ private Boolean validate( TypeMirror typeMirror )
+ {
+ return allowedTypesValidator.test( typeMirror );
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/ParameterVisitor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/ParameterVisitor.java
new file mode 100644
index 0000000000000..1351d3e31371a
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/ParameterVisitor.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.visitors;
+
+import org.neo4j.tooling.procedure.messages.CompilationMessage;
+import org.neo4j.tooling.procedure.messages.ParameterMissingAnnotationError;
+import org.neo4j.tooling.procedure.messages.ParameterTypeError;
+
+import java.util.List;
+import java.util.stream.Stream;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.util.SimpleElementVisitor8;
+
+import org.neo4j.procedure.Name;
+
+class ParameterVisitor extends SimpleElementVisitor8,Void>
+{
+
+ private final TypeVisitor parameterTypeVisitor;
+
+ public ParameterVisitor( TypeVisitor parameterTypeVisitor )
+ {
+ this.parameterTypeVisitor = parameterTypeVisitor;
+ }
+
+ @Override
+ public Stream visitVariable( VariableElement parameter, Void ignored )
+ {
+ Name annotation = parameter.getAnnotation( Name.class );
+ if ( annotation == null )
+ {
+ return Stream.of( new ParameterMissingAnnotationError( parameter,
+ annotationMirror( parameter.getAnnotationMirrors() ), "@%s usage error: missing on parameter <%s>",
+ Name.class.getName(), nameOf( parameter ) ) );
+ }
+
+ if ( !parameterTypeVisitor.visit( parameter.asType() ) )
+ {
+ Element method = parameter.getEnclosingElement();
+ return Stream.of( new ParameterTypeError( parameter,
+ "Unsupported parameter type <%s> of " + "procedure|function" + " %s#%s",
+ parameter.asType().toString(), method.getEnclosingElement().getSimpleName(),
+ method.getSimpleName() ) );
+ }
+ return Stream.empty();
+ }
+
+ private AnnotationMirror annotationMirror( List extends AnnotationMirror> mirrors )
+ {
+ AnnotationTypeVisitor nameVisitor = new AnnotationTypeVisitor( Name.class );
+ return mirrors.stream().filter( mirror -> nameVisitor.visit( mirror.getAnnotationType().asElement() ) )
+ .findFirst().orElse( null );
+ }
+
+ private String nameOf( VariableElement parameter )
+ {
+ return parameter.getSimpleName().toString();
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/PerformsWriteMethodVisitor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/PerformsWriteMethodVisitor.java
new file mode 100644
index 0000000000000..21b5c61ba5a3b
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/PerformsWriteMethodVisitor.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.visitors;
+
+import org.neo4j.tooling.procedure.messages.CompilationMessage;
+import org.neo4j.tooling.procedure.messages.PerformsWriteMisuseError;
+
+import java.util.stream.Stream;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.util.SimpleElementVisitor8;
+
+import org.neo4j.procedure.Mode;
+import org.neo4j.procedure.PerformsWrites;
+import org.neo4j.procedure.Procedure;
+
+public class PerformsWriteMethodVisitor extends SimpleElementVisitor8,Void>
+{
+
+ @Override
+ public Stream visitExecutable( ExecutableElement method, Void ignored )
+ {
+ Procedure procedure = method.getAnnotation( Procedure.class );
+ if ( procedure == null )
+ {
+ return Stream.of( new PerformsWriteMisuseError( method, "@%s usage error: missing @%s annotation on method",
+ PerformsWrites.class.getSimpleName(), Procedure.class.getSimpleName() ) );
+ }
+
+ if ( procedure.mode() != Mode.DEFAULT )
+ {
+ return Stream.of( new PerformsWriteMisuseError( method,
+ "@%s usage error: cannot use mode other than Mode.DEFAULT",
+ PerformsWrites.class.getSimpleName() ) );
+ }
+ return Stream.empty();
+ }
+
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/RecordFieldTypeVisitor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/RecordFieldTypeVisitor.java
new file mode 100644
index 0000000000000..04f8eb74884e2
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/RecordFieldTypeVisitor.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.visitors;
+
+import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils;
+import org.neo4j.tooling.procedure.validators.AllowedTypesValidator;
+
+import java.util.function.Predicate;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor8;
+import javax.lang.model.util.Types;
+
+class RecordFieldTypeVisitor extends SimpleTypeVisitor8
+{
+
+ private final Predicate allowedTypesValidator;
+
+ public RecordFieldTypeVisitor( Types typeUtils, TypeMirrorUtils typeMirrors )
+ {
+ allowedTypesValidator = new AllowedTypesValidator( typeMirrors, typeUtils );
+ }
+
+ @Override
+ public Boolean visitDeclared( DeclaredType declaredType, Void ignored )
+ {
+ return allowedTypesValidator.test( declaredType ) &&
+ declaredType.getTypeArguments().stream().map( this::visit ).reduce( ( a, b ) -> a && b ).orElse( true );
+ }
+
+ @Override
+ public Boolean visitPrimitive( PrimitiveType primitiveType, Void ignored )
+ {
+ return allowedTypesValidator.test( primitiveType );
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/RecordTypeVisitor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/RecordTypeVisitor.java
new file mode 100644
index 0000000000000..fda5fa10738d6
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/RecordTypeVisitor.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.visitors;
+
+import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils;
+import org.neo4j.tooling.procedure.messages.CompilationMessage;
+import org.neo4j.tooling.procedure.messages.RecordTypeError;
+
+import java.util.Set;
+import java.util.stream.Stream;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.util.SimpleTypeVisitor8;
+import javax.lang.model.util.Types;
+
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+import static javax.lang.model.util.ElementFilter.fieldsIn;
+
+class RecordTypeVisitor extends SimpleTypeVisitor8,Void>
+{
+
+ private final Types typeUtils;
+ private final TypeVisitor fieldTypeVisitor;
+
+ public RecordTypeVisitor( Types typeUtils, TypeMirrorUtils typeMirrors )
+ {
+ this.typeUtils = typeUtils;
+ fieldTypeVisitor = new RecordFieldTypeVisitor( typeUtils, typeMirrors );
+ }
+
+ @Override
+ public Stream visitDeclared( DeclaredType returnType, Void ignored )
+ {
+ return returnType.getTypeArguments().stream().flatMap( this::validateRecord );
+ }
+
+ private Stream validateRecord( TypeMirror recordType )
+ {
+ Element recordElement = typeUtils.asElement( recordType );
+ return Stream.concat( validateFieldModifiers( recordElement ), validateFieldType( recordElement ) );
+ }
+
+ private Stream validateFieldModifiers( Element recordElement )
+ {
+ return fieldsIn( recordElement.getEnclosedElements() ).stream().filter( element ->
+ {
+ Set modifiers = element.getModifiers();
+ return !modifiers.contains( PUBLIC ) && !modifiers.contains( STATIC );
+ } ).map( element -> new RecordTypeError( element, "Record definition error: field %s#%s must be public",
+ recordElement.getSimpleName(), element.getSimpleName() ) );
+ }
+
+ private Stream validateFieldType( Element recordElement )
+ {
+ return fieldsIn( recordElement.getEnclosedElements() ).stream()
+ .filter( element -> !element.getModifiers().contains( STATIC ) )
+ .filter( element -> !fieldTypeVisitor.visit( element.asType() ) )
+ .map( element -> new RecordTypeError( element,
+ "Record definition error: type of field %s#%s is not supported", recordElement.getSimpleName(),
+ element.getSimpleName() ) );
+ }
+
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/StoredProcedureClassVisitor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/StoredProcedureClassVisitor.java
new file mode 100644
index 0000000000000..4134ffb9d28ad
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/StoredProcedureClassVisitor.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.visitors;
+
+import org.neo4j.tooling.procedure.messages.CompilationMessage;
+import org.neo4j.tooling.procedure.messages.ProcedureMissingPublicNoArgConstructor;
+
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleElementVisitor8;
+import javax.lang.model.util.Types;
+
+import static javax.lang.model.util.ElementFilter.constructorsIn;
+
+public class StoredProcedureClassVisitor extends SimpleElementVisitor8,Void>
+{
+
+ private final Set visitedElements = new HashSet<>();
+ private final FieldVisitor fieldVisitor;
+
+ public StoredProcedureClassVisitor( Types types, Elements elements, boolean skipContextWarnings )
+ {
+ fieldVisitor = new FieldVisitor( types, elements, skipContextWarnings );
+ }
+
+ @Override
+ public Stream visitType( TypeElement procedureClass, Void ignored )
+ {
+ if ( isFirstVisit( procedureClass ) )
+ {
+ return Stream.concat( validateFields( procedureClass ), validateConstructor( procedureClass ) );
+ }
+ return Stream.empty();
+ }
+
+ /**
+ * Check if the {@link TypeElement} is visited for the first time. A {@link TypeElement} will be visited once per
+ * procedure it contains, but it only needs to be validated once.
+ *
+ * @param e The visited {@link TypeElement}
+ * @return true for the first visit of the {@link TypeElement}, false afterwards
+ */
+ private boolean isFirstVisit( TypeElement e )
+ {
+ return visitedElements.add( e );
+ }
+
+ private Stream validateFields( TypeElement e )
+ {
+ return e.getEnclosedElements().stream().flatMap( fieldVisitor::visit );
+ }
+
+ private Stream validateConstructor( Element procedureClass )
+ {
+ Optional publicNoArgConstructor =
+ constructorsIn( procedureClass.getEnclosedElements() ).stream()
+ .filter( c -> c.getModifiers().contains( Modifier.PUBLIC ) )
+ .filter( c -> c.getParameters().isEmpty() ).findFirst();
+
+ if ( !publicNoArgConstructor.isPresent() )
+ {
+ return Stream.of( new ProcedureMissingPublicNoArgConstructor( procedureClass,
+ "Procedure class %s should contain a public no-arg constructor, none found.", procedureClass ) );
+ }
+ return Stream.empty();
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/StoredProcedureVisitor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/StoredProcedureVisitor.java
new file mode 100644
index 0000000000000..c4fbe5a160dad
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/StoredProcedureVisitor.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.visitors;
+
+import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils;
+import org.neo4j.tooling.procedure.messages.CompilationMessage;
+import org.neo4j.tooling.procedure.messages.ReturnTypeError;
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleElementVisitor8;
+import javax.lang.model.util.Types;
+
+import org.neo4j.procedure.Name;
+
+public class StoredProcedureVisitor extends SimpleElementVisitor8,Void>
+{
+
+ private final Types typeUtils;
+ private final Elements elementUtils;
+ private final ElementVisitor,Void> classVisitor;
+ private final TypeVisitor,Void> recordVisitor;
+ private final ElementVisitor,Void> parameterVisitor;
+
+ public StoredProcedureVisitor( Types typeUtils, Elements elementUtils, boolean skipContextWarnings )
+ {
+ TypeMirrorUtils typeMirrors = new TypeMirrorUtils( typeUtils, elementUtils );
+
+ this.typeUtils = typeUtils;
+ this.elementUtils = elementUtils;
+ this.classVisitor = new StoredProcedureClassVisitor( typeUtils, elementUtils, skipContextWarnings );
+ this.recordVisitor = new RecordTypeVisitor( typeUtils, typeMirrors );
+ this.parameterVisitor = new ParameterVisitor( new ParameterTypeVisitor( typeUtils, typeMirrors ) );
+ }
+
+ /**
+ * Validates method parameters and return type
+ */
+ @Override
+ public Stream visitExecutable( ExecutableElement executableElement, Void ignored )
+ {
+ return Stream.of( classVisitor.visit( executableElement.getEnclosingElement() ),
+ validateParameters( executableElement.getParameters(), ignored ),
+ validateReturnType( executableElement ) ).flatMap( Function.identity() );
+ }
+
+ private Stream validateParameters( List extends VariableElement> parameters, Void ignored )
+ {
+ return parameters.stream().flatMap( var -> parameterVisitor.visit( var, ignored ) );
+ }
+
+ private Stream validateReturnType( ExecutableElement method )
+ {
+ String streamClassName = Stream.class.getCanonicalName();
+
+ TypeMirror streamType = typeUtils.erasure( elementUtils.getTypeElement( streamClassName ).asType() );
+ TypeMirror returnType = method.getReturnType();
+ TypeMirror erasedReturnType = typeUtils.erasure( returnType );
+
+ TypeMirror voidType = typeUtils.getNoType( TypeKind.VOID );
+ if ( typeUtils.isSameType( returnType, voidType ) )
+ {
+ return Stream.empty();
+ }
+
+ if ( !typeUtils.isSubtype( erasedReturnType, streamType ) )
+ {
+ return Stream.of( new ReturnTypeError( method, "Return type of %s#%s must be %s",
+ method.getEnclosingElement().getSimpleName(), method.getSimpleName(), streamClassName ) );
+ }
+
+ return recordVisitor.visit( returnType );
+ }
+
+ private AnnotationMirror annotationMirror( List extends AnnotationMirror> mirrors )
+ {
+ AnnotationTypeVisitor nameVisitor = new AnnotationTypeVisitor( Name.class );
+ return mirrors.stream().filter( mirror -> nameVisitor.visit( mirror.getAnnotationType().asElement() ) )
+ .findFirst().orElse( null );
+ }
+
+ private String nameOf( VariableElement parameter )
+ {
+ return parameter.getSimpleName().toString();
+ }
+}
diff --git a/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/UserFunctionVisitor.java b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/UserFunctionVisitor.java
new file mode 100644
index 0000000000000..737cabe9be343
--- /dev/null
+++ b/community/procedure-compiler/processor/src/main/java/org/neo4j/tooling/procedure/visitors/UserFunctionVisitor.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.visitors;
+
+import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils;
+import org.neo4j.tooling.procedure.messages.CompilationMessage;
+import org.neo4j.tooling.procedure.messages.FunctionInRootNamespaceError;
+import org.neo4j.tooling.procedure.messages.ReturnTypeError;
+import org.neo4j.tooling.procedure.validators.AllowedTypesValidator;
+
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleElementVisitor8;
+import javax.lang.model.util.Types;
+
+import org.neo4j.procedure.UserFunction;
+
+public class UserFunctionVisitor extends SimpleElementVisitor8,Void>
+{
+
+ private final ElementVisitor,Void> parameterVisitor;
+ private final Predicate allowedTypesValidator;
+ private final Elements elements;
+
+ public UserFunctionVisitor( Types types, Elements elements, TypeMirrorUtils typeMirrorUtils )
+ {
+ this.parameterVisitor = new ParameterVisitor( new ParameterTypeVisitor( types, typeMirrorUtils ) );
+ this.allowedTypesValidator = new AllowedTypesValidator( typeMirrorUtils, types );
+ this.elements = elements;
+ }
+
+ @Override
+ public Stream visitExecutable( ExecutableElement method, Void ignored )
+ {
+ return Stream
+ .concat( Stream.concat( validateParameters( method.getParameters(), ignored ), validateName( method ) ),
+ validateReturnType( method ) );
+ }
+
+ private Stream validateParameters( List extends VariableElement> parameters, Void ignored )
+ {
+ return parameters.stream().flatMap( var -> parameterVisitor.visit( var, ignored ) );
+ }
+
+ private Stream validateName( ExecutableElement method )
+ {
+ UserFunction function = method.getAnnotation( UserFunction.class );
+ String name = function.name();
+ if ( !name.isEmpty() && isInRootNamespace( name ) )
+ {
+ return Stream.of( rootNamespaceError( method, name ) );
+ }
+ String value = function.value();
+ if ( !value.isEmpty() && isInRootNamespace( value ) )
+ {
+ return Stream.of( rootNamespaceError( method, value ) );
+ }
+ PackageElement namespace = elements.getPackageOf( method );
+ if ( namespace == null )
+ {
+ return Stream.of( rootNamespaceError( method ) );
+ }
+ return Stream.empty();
+ }
+
+ private Stream validateReturnType( ExecutableElement method )
+ {
+ TypeMirror returnType = method.getReturnType();
+ if ( !allowedTypesValidator.test( returnType ) )
+ {
+ return Stream.of( new ReturnTypeError( method,
+ "Unsupported return type <%s> of function defined in " + "<%s#%s>.", returnType,
+ method.getEnclosingElement(), method.getSimpleName() ) );
+ }
+ return Stream.empty();
+ }
+
+ private boolean isInRootNamespace( String name )
+ {
+ return !name.contains( "." ) || name.split( "\\." )[0].isEmpty();
+ }
+
+ private FunctionInRootNamespaceError rootNamespaceError( ExecutableElement method, String name )
+ {
+ return new FunctionInRootNamespaceError( method,
+ "Function <%s> cannot be defined in the root namespace. Valid name example: com.acme.my_function",
+ name );
+ }
+
+ private FunctionInRootNamespaceError rootNamespaceError( ExecutableElement method )
+ {
+ return new FunctionInRootNamespaceError( method,
+ "Function defined in <%s#%s> cannot be defined in the root namespace. " +
+ "Valid name example: com.acme.my_function", method.getEnclosingElement().getSimpleName(),
+ method.getSimpleName() );
+ }
+
+}
diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/PerformsWriteProcessorTest.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/PerformsWriteProcessorTest.java
new file mode 100644
index 0000000000000..e6775e59c1d21
--- /dev/null
+++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/PerformsWriteProcessorTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure;
+
+import com.google.testing.compile.CompilationRule;
+import org.neo4j.tooling.procedure.testutils.JavaFileObjectUtils;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.annotation.processing.Processor;
+import javax.tools.JavaFileObject;
+
+import static com.google.common.truth.Truth.assert_;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+
+public class PerformsWriteProcessorTest
+{
+ @Rule
+ public CompilationRule compilation = new CompilationRule();
+
+ private Processor processor = new PerformsWriteProcessor();
+
+ @Test
+ public void fails_with_conflicting_mode()
+ {
+ JavaFileObject procedure = JavaFileObjectUtils.INSTANCE.procedureSource(
+ "invalid/conflicting_mode/ConflictingMode.java" );
+
+ assert_().about( javaSource() ).that( procedure ).processedWith( processor ).failsToCompile()
+ .withErrorCount( 1 )
+ .withErrorContaining( "@PerformsWrites usage error: cannot use mode other than Mode.DEFAULT" )
+ .in( procedure ).onLine( 30 );
+
+ }
+}
diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/ProcedureProcessorTest.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/ProcedureProcessorTest.java
new file mode 100644
index 0000000000000..2fb43ab38f38b
--- /dev/null
+++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/ProcedureProcessorTest.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure;
+
+import com.google.testing.compile.CompilationRule;
+import com.google.testing.compile.CompileTester.UnsuccessfulCompilationClause;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.annotation.processing.Processor;
+import javax.tools.JavaFileObject;
+
+import org.neo4j.tooling.procedure.testutils.JavaFileObjectUtils;
+
+import static com.google.common.truth.Truth.assert_;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static java.util.Arrays.asList;
+
+public class ProcedureProcessorTest
+{
+
+ @Rule
+ public CompilationRule compilation = new CompilationRule();
+
+ private Processor processor = new ProcedureProcessor();
+
+ @Test
+ public void fails_if_parameters_are_not_properly_annotated()
+ {
+ JavaFileObject sproc =
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/missing_name/MissingNameSproc.java" );
+
+ UnsuccessfulCompilationClause compilation =
+ assert_().about( javaSource() ).that( sproc ).processedWith( processor ).failsToCompile()
+ .withErrorCount( 2 );
+
+ compilation.withErrorContaining( "@org.neo4j.procedure.Name usage error: missing on parameter " )
+ .in( sproc ).onLine( 35 );
+
+ compilation.withErrorContaining( "@org.neo4j.procedure.Name usage error: missing on parameter " )
+ .in( sproc ).onLine( 35 );
+ }
+
+ @Test
+ public void fails_if_return_type_is_not_stream()
+ {
+ JavaFileObject sproc =
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/bad_return_type/BadReturnTypeSproc.java" );
+
+ assert_().about( javaSource() ).that( sproc ).processedWith( processor ).failsToCompile().withErrorCount( 1 )
+ .withErrorContaining( "Return type of BadReturnTypeSproc#niceSproc must be java.util.stream.Stream" )
+ .in( sproc ).onLine( 34 );
+ }
+
+ @Test
+ public void fails_if_record_type_has_nonpublic_fields()
+ {
+ JavaFileObject record =
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/bad_record_type/BadRecord.java" );
+
+ UnsuccessfulCompilationClause compilation = assert_().about( javaSources() ).that( asList(
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/bad_record_type/BadRecordTypeSproc.java" ),
+ record ) ).processedWith( processor ).failsToCompile().withErrorCount( 2 );
+
+ compilation.withErrorContaining( "Record definition error: field BadRecord#label must be public" ).in( record )
+ .onLine( 26 );
+
+ compilation.withErrorContaining( "Record definition error: field BadRecord#age must be public" ).in( record )
+ .onLine( 27 );
+ }
+
+ @Test
+ public void fails_if_procedure_primitive_input_type_is_not_supported()
+ {
+ JavaFileObject sproc = JavaFileObjectUtils.INSTANCE
+ .procedureSource( "invalid/bad_proc_input_type/BadPrimitiveInputSproc.java" );
+
+ assert_().about( javaSource() ).that( sproc ).processedWith( processor ).failsToCompile().withErrorCount( 1 )
+ .withErrorContaining(
+ "Unsupported parameter type of procedure|function BadPrimitiveInputSproc#doSomething" )
+ .in( sproc ).onLine( 32 );
+ }
+
+ @Test
+ public void fails_if_procedure_generic_input_type_is_not_supported()
+ {
+ JavaFileObject sproc =
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/bad_proc_input_type/BadGenericInputSproc.java" );
+
+ UnsuccessfulCompilationClause compilation =
+ assert_().about( javaSource() ).that( sproc ).processedWith( processor ).failsToCompile()
+ .withErrorCount( 3 );
+
+ compilation.withErrorContaining( "Unsupported parameter type " +
+ ">>>" +
+ " of procedure|function BadGenericInputSproc#doSomething" ).in( sproc ).onLine( 36 );
+
+ compilation.withErrorContaining( "Unsupported parameter type " +
+ ">>" +
+ " of procedure|function BadGenericInputSproc#doSomething2" ).in( sproc ).onLine( 42 );
+
+ compilation.withErrorContaining(
+ "Unsupported parameter type of procedure|function BadGenericInputSproc#doSomething3" )
+ .in( sproc ).onLine( 48 );
+ }
+
+ @Test
+ public void fails_if_procedure_primitive_record_field_type_is_not_supported()
+ {
+ JavaFileObject record = JavaFileObjectUtils.INSTANCE
+ .procedureSource( "invalid/bad_record_field_type/BadRecordSimpleFieldType.java" );
+
+ assert_().about( javaSources() ).that( asList( JavaFileObjectUtils.INSTANCE
+ .procedureSource( "invalid/bad_record_field_type/BadRecordSimpleFieldTypeSproc.java" ), record ) )
+ .processedWith( processor ).failsToCompile().withErrorCount( 1 ).withErrorContaining(
+ "Record definition error: type of field BadRecordSimpleFieldType#wrongType is not supported" )
+ .in( record ).onLine( 29 );
+ }
+
+ @Test
+ public void fails_if_procedure_generic_record_field_type_is_not_supported()
+ {
+ JavaFileObject record = JavaFileObjectUtils.INSTANCE
+ .procedureSource( "invalid/bad_record_field_type/BadRecordGenericFieldType.java" );
+
+ UnsuccessfulCompilationClause compilation = assert_().about( javaSources() ).that( asList(
+ JavaFileObjectUtils.INSTANCE
+ .procedureSource( "invalid/bad_record_field_type/BadRecordGenericFieldTypeSproc.java" ),
+ record ) ).processedWith( processor ).failsToCompile().withErrorCount( 3 );
+
+ compilation.withErrorContaining(
+ "Record definition error: type of field BadRecordGenericFieldType#wrongType1 is not supported" )
+ .in( record ).onLine( 34 );
+ compilation.withErrorContaining(
+ "Record definition error: type of field BadRecordGenericFieldType#wrongType2 is not supported" )
+ .in( record ).onLine( 35 );
+ compilation.withErrorContaining(
+ "Record definition error: type of field BadRecordGenericFieldType#wrongType3 is not supported" )
+ .in( record ).onLine( 36 );
+ }
+
+ @Test
+ public void fails_if_duplicate_procedures_are_declared()
+ {
+ JavaFileObject firstDuplicate =
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/duplicated/Sproc1.java" );
+ JavaFileObject secondDuplicate =
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/duplicated/Sproc2.java" );
+
+ assert_().about( javaSources() ).that( asList( firstDuplicate, secondDuplicate ) ).processedWith( processor )
+ .failsToCompile().withErrorCount( 2 ).withErrorContaining(
+ "Procedure|function name is " +
+ "already defined 2 times. It should be defined only once!" );
+ }
+
+ @Test
+ public void fails_if_procedure_class_has_no_public_no_arg_constructor()
+ {
+ JavaFileObject procedure = JavaFileObjectUtils.INSTANCE
+ .procedureSource( "invalid/missing_constructor/MissingConstructorProcedure.java" );
+
+ assert_().about( javaSource() ).that( procedure ).processedWith( processor ).failsToCompile()
+ .withErrorCount( 1 ).withErrorContaining(
+ "Procedure class org.neo4j.tooling.procedure.procedures.invalid.missing_constructor.MissingConstructorProcedure should contain a public no-arg constructor, none found." )
+ .in( procedure ).onLine( 24 );
+ }
+
+ @Test
+ public void succeeds_to_process_valid_stored_procedures()
+ {
+ assert_().about( javaSources() )
+ .that( asList( JavaFileObjectUtils.INSTANCE.procedureSource( "valid/Procedures.java" ),
+ JavaFileObjectUtils.INSTANCE.procedureSource( "valid/Records.java" ) ) )
+ .processedWith( processor ).compilesWithoutError();
+
+ }
+
+ @Test
+ public void fails_if_context_injected_fields_have_wrong_modifiers()
+ {
+ JavaFileObject sproc =
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/bad_context_field/BadContextSproc.java" );
+
+ UnsuccessfulCompilationClause unsuccessfulCompilationClause =
+ assert_().about( javaSource() ).that( sproc ).processedWith( processor ).failsToCompile()
+ .withErrorCount( 4 );
+
+ unsuccessfulCompilationClause.withErrorContaining(
+ "@org.neo4j.procedure.Context usage error: field BadContextSproc#shouldBeNonStatic should be public, non-static and non-final" )
+ .in( sproc ).onLine( 30 );
+
+ unsuccessfulCompilationClause.withErrorContaining(
+ "@org.neo4j.procedure.Context usage error: field BadContextSproc#shouldBeNonFinal should be public, non-static and non-final" )
+ .in( sproc ).onLine( 33 );
+
+ unsuccessfulCompilationClause.withErrorContaining(
+ "@org.neo4j.procedure.Context usage error: field BadContextSproc#shouldBePublic should be public, non-static and non-final" )
+ .in( sproc ).onLine( 37 );
+
+ unsuccessfulCompilationClause.withErrorContaining( "Field BadContextSproc#shouldBeStatic should be static" )
+ .in( sproc ).onLine( 38 );
+ }
+
+ @Test
+ public void emits_warnings_if_context_injected_field_types_are_unsupported()
+ {
+ JavaFileObject sproc =
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/bad_context_field/BadContextTypeSproc.java" );
+
+ assert_().about( javaSource() ).that( sproc ).processedWith( processor ).compilesWithoutError()
+ .withWarningCount( 2 ).withWarningContaining(
+ "@org.neo4j.procedure.Context usage warning: found type: , expected one of: , " )
+ .in( sproc ).onLine( 30 );
+ }
+
+ @Test
+ public void does_not_emit_warnings_if_context_injected_field_types_are_unsupported_when_context_warnings_disabled()
+ {
+ JavaFileObject sproc =
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/bad_context_field/BadContextTypeSproc.java" );
+
+ assert_().about( javaSource() ).that( sproc ).withCompilerOptions( "-AIgnoreContextWarnings" )
+ .processedWith( processor ).compilesWithoutError().withWarningCount( 1 );
+ }
+}
diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/UserFunctionProcessorTest.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/UserFunctionProcessorTest.java
new file mode 100644
index 0000000000000..4032a47dafeea
--- /dev/null
+++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/UserFunctionProcessorTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure;
+
+import com.google.testing.compile.CompilationRule;
+import com.google.testing.compile.CompileTester.UnsuccessfulCompilationClause;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.annotation.processing.Processor;
+import javax.tools.JavaFileObject;
+
+import org.neo4j.tooling.procedure.testutils.JavaFileObjectUtils;
+
+import static com.google.common.truth.Truth.assert_;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static java.util.Arrays.asList;
+
+public class UserFunctionProcessorTest
+{
+
+ @Rule
+ public CompilationRule compilation = new CompilationRule();
+
+ private Processor processor = new UserFunctionProcessor();
+
+ @Test
+ public void fails_if_parameters_are_not_properly_annotated()
+ {
+ JavaFileObject function =
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/missing_name/MissingNameUserFunction.java" );
+
+ UnsuccessfulCompilationClause compilation =
+ assert_().about( javaSource() ).that( function ).processedWith( processor ).failsToCompile()
+ .withErrorCount( 2 );
+
+ compilation.withErrorContaining( "@org.neo4j.procedure.Name usage error: missing on parameter " )
+ .in( function ).onLine( 28 );
+
+ compilation.withErrorContaining( "@org.neo4j.procedure.Name usage error: missing on parameter " )
+ .in( function ).onLine( 28 );
+ }
+
+ @Test
+ public void fails_if_return_type_is_incorrect()
+ {
+ JavaFileObject function = JavaFileObjectUtils.INSTANCE
+ .procedureSource( "invalid/bad_return_type/BadReturnTypeUserFunction.java" );
+
+ assert_().about( javaSource() ).that( function ).processedWith( processor ).failsToCompile().withErrorCount( 1 )
+ .withErrorContaining(
+ "Unsupported return type > of function defined in " )
+ .in( function ).onLine( 36 );
+ }
+
+ @Test
+ public void fails_if_function_primitive_input_type_is_not_supported()
+ {
+ JavaFileObject function = JavaFileObjectUtils.INSTANCE
+ .procedureSource( "invalid/bad_proc_input_type/BadPrimitiveInputUserFunction.java" );
+
+ assert_().about( javaSource() ).that( function ).processedWith( processor ).failsToCompile().withErrorCount( 1 )
+ .withErrorContaining(
+ "Unsupported parameter type of procedure|function BadPrimitiveInputUserFunction#doSomething" )
+ .in( function ).onLine( 32 );
+ }
+
+ @Test
+ public void fails_if_function_generic_input_type_is_not_supported()
+ {
+ JavaFileObject function = JavaFileObjectUtils.INSTANCE
+ .procedureSource( "invalid/bad_proc_input_type/BadGenericInputUserFunction.java" );
+
+ UnsuccessfulCompilationClause compilation =
+ assert_().about( javaSource() ).that( function ).processedWith( processor ).failsToCompile()
+ .withErrorCount( 3 );
+
+ compilation.withErrorContaining( "Unsupported parameter type " +
+ ">>>" +
+ " of procedure|function BadGenericInputUserFunction#doSomething" ).in( function ).onLine( 36 );
+
+ compilation.withErrorContaining( "Unsupported parameter type " +
+ ">>" +
+ " of procedure|function BadGenericInputUserFunction#doSomething2" ).in( function ).onLine( 42 );
+
+ compilation.withErrorContaining(
+ "Unsupported parameter type of procedure|function BadGenericInputUserFunction#doSomething3" )
+ .in( function ).onLine( 48 );
+ }
+
+ @Test
+ public void fails_if_duplicate_functions_are_declared()
+ {
+ JavaFileObject firstDuplicate =
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/duplicated/UserFunction1.java" );
+ JavaFileObject secondDuplicate =
+ JavaFileObjectUtils.INSTANCE.procedureSource( "invalid/duplicated/UserFunction2.java" );
+
+ assert_().about( javaSources() ).that( asList( firstDuplicate, secondDuplicate ) ).processedWith( processor )
+ .failsToCompile().withErrorCount( 2 ).withErrorContaining(
+ "Procedure|function name is already defined 2 times. It should be defined only once!" );
+ }
+
+ @Test
+ public void succeeds_to_process_valid_stored_procedures()
+ {
+ assert_().about( javaSource() )
+ .that( JavaFileObjectUtils.INSTANCE.procedureSource( "valid/UserFunctions.java" ) )
+ .processedWith( processor ).compilesWithoutError();
+
+ }
+}
diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_context_field/BadContextSproc.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_context_field/BadContextSproc.java
new file mode 100644
index 0000000000000..dee4082f9ca0d
--- /dev/null
+++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_context_field/BadContextSproc.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.procedures.invalid.bad_context_field;
+
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.procedure.Context;
+import org.neo4j.procedure.Procedure;
+
+public class BadContextSproc
+{
+
+ @Context
+ public static GraphDatabaseService shouldBeNonStatic;
+ public static String value;
+ @Context
+ public final GraphDatabaseService shouldBeNonFinal = null;
+ @Context
+ public GraphDatabaseService db;
+ @Context
+ protected GraphDatabaseService shouldBePublic;
+ String shouldBeStatic;
+
+ @Procedure
+ public void sproc1()
+ {
+ }
+
+ @Procedure
+ public void sproc2()
+ {
+ }
+}
diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_context_field/BadContextTypeSproc.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_context_field/BadContextTypeSproc.java
new file mode 100644
index 0000000000000..0a887881d74e4
--- /dev/null
+++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_context_field/BadContextTypeSproc.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.procedures.invalid.bad_context_field;
+
+import org.neo4j.kernel.internal.GraphDatabaseAPI;
+import org.neo4j.procedure.Context;
+import org.neo4j.procedure.Procedure;
+
+public class BadContextTypeSproc
+{
+
+ @Context
+ public GraphDatabaseAPI notOfficiallySupported;
+
+ @Procedure
+ public void sproc()
+ {
+ }
+}
diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_proc_input_type/BadGenericInputSproc.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_proc_input_type/BadGenericInputSproc.java
new file mode 100644
index 0000000000000..0c87db162508f
--- /dev/null
+++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_proc_input_type/BadGenericInputSproc.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.procedures.invalid.bad_proc_input_type;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Path;
+import org.neo4j.graphdb.Relationship;
+import org.neo4j.procedure.Name;
+import org.neo4j.procedure.Procedure;
+
+public class BadGenericInputSproc
+{
+
+ @Procedure
+ public void doSomething( @Name( "test" ) List>> unsupportedType )
+ {
+
+ }
+
+ @Procedure
+ public void doSomething2( @Name( "test" ) Map> unsupportedType )
+ {
+
+ }
+
+ @Procedure
+ public void doSomething3( @Name( "test" ) Map unsupportedType )
+ {
+
+ }
+
+ @Procedure
+ public void works1( @Name( "test" ) List supported )
+ {
+ }
+
+ @Procedure
+ public void works2( @Name( "test" ) List> supported )
+ {
+ }
+
+ @Procedure
+ public void works3( @Name( "test" ) Map supported )
+ {
+ }
+
+ @Procedure
+ public void works4( @Name( "test" ) List>>> supported )
+ {
+ }
+
+ @Procedure
+ public void works5( @Name( "test" ) List>> supported )
+ {
+ }
+
+ @Procedure
+ public void works6( @Name( "test" ) List supported )
+ {
+ }
+
+ @Procedure
+ public void works7( @Name( "test" ) List> supported )
+ {
+ }
+
+ @Procedure
+ public void works8( @Name( "test" ) Map>> supported )
+ {
+ }
+
+ @Procedure
+ public void works9( @Name( "test" ) Map>> supported )
+ {
+ }
+}
diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_proc_input_type/BadGenericInputUserFunction.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_proc_input_type/BadGenericInputUserFunction.java
new file mode 100644
index 0000000000000..df90943f77549
--- /dev/null
+++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_proc_input_type/BadGenericInputUserFunction.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.procedures.invalid.bad_proc_input_type;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Path;
+import org.neo4j.graphdb.Relationship;
+import org.neo4j.procedure.Name;
+import org.neo4j.procedure.UserFunction;
+
+public class BadGenericInputUserFunction
+{
+
+ @UserFunction
+ public String doSomething( @Name( "test" ) List>> unsupportedType )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String doSomething2( @Name( "test" ) Map> unsupportedType )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String doSomething3( @Name( "test" ) Map unsupportedType )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works1( @Name( "test" ) List supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works2( @Name( "test" ) List> supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works3( @Name( "test" ) Map supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works4( @Name( "test" ) List>>> supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works5( @Name( "test" ) List>> supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works6( @Name( "test" ) List supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works7( @Name( "test" ) List> supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works8( @Name( "test" ) Map>> supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works9( @Name( "test" ) Map>> supported )
+ {
+ return "42";
+ }
+}
diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_proc_input_type/BadPrimitiveInputSproc.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_proc_input_type/BadPrimitiveInputSproc.java
new file mode 100644
index 0000000000000..49605528fbfa1
--- /dev/null
+++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_proc_input_type/BadPrimitiveInputSproc.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.procedures.invalid.bad_proc_input_type;
+
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Path;
+import org.neo4j.graphdb.Relationship;
+import org.neo4j.procedure.Name;
+import org.neo4j.procedure.Procedure;
+
+public class BadPrimitiveInputSproc
+{
+
+ @Procedure
+ public void doSomething( @Name( "test" ) short unsupportedType )
+ {
+
+ }
+
+ @Procedure
+ public void works01( @Name( "test" ) String supported )
+ {
+ }
+
+ @Procedure
+ public void works02( @Name( "test" ) Long supported )
+ {
+ }
+
+ @Procedure
+ public void works03( @Name( "test" ) long supported )
+ {
+ }
+
+ @Procedure
+ public void works04( @Name( "test" ) Double supported )
+ {
+ }
+
+ @Procedure
+ public void works05( @Name( "test" ) double supported )
+ {
+ }
+
+ @Procedure
+ public void works06( @Name( "test" ) Number supported )
+ {
+ }
+
+ @Procedure
+ public void works07( @Name( "test" ) Boolean supported )
+ {
+ }
+
+ @Procedure
+ public void works08( @Name( "test" ) boolean supported )
+ {
+ }
+
+ @Procedure
+ public void works09( @Name( "test" ) Object supported )
+ {
+ }
+
+ @Procedure
+ public void works10( @Name( "test" ) Node supported )
+ {
+ }
+
+ @Procedure
+ public void works11( @Name( "test" ) Relationship supported )
+ {
+ }
+
+ @Procedure
+ public void works12( @Name( "test" ) Path supported )
+ {
+ }
+}
diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_proc_input_type/BadPrimitiveInputUserFunction.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_proc_input_type/BadPrimitiveInputUserFunction.java
new file mode 100644
index 0000000000000..b1e9c0bc1b0b9
--- /dev/null
+++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_proc_input_type/BadPrimitiveInputUserFunction.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.procedures.invalid.bad_proc_input_type;
+
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Path;
+import org.neo4j.graphdb.Relationship;
+import org.neo4j.procedure.Name;
+import org.neo4j.procedure.UserFunction;
+
+public class BadPrimitiveInputUserFunction
+{
+
+ @UserFunction
+ public String doSomething( @Name( "test" ) short unsupportedType )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works01( @Name( "test" ) String supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works02( @Name( "test" ) Long supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works03( @Name( "test" ) long supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works04( @Name( "test" ) Double supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works05( @Name( "test" ) double supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works06( @Name( "test" ) Number supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works07( @Name( "test" ) Boolean supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works08( @Name( "test" ) boolean supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works09( @Name( "test" ) Object supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works10( @Name( "test" ) Node supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works11( @Name( "test" ) Relationship supported )
+ {
+ return "42";
+ }
+
+ @UserFunction
+ public String works12( @Name( "test" ) Path supported )
+ {
+ return "42";
+ }
+}
diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_field_type/BadRecordGenericFieldType.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_field_type/BadRecordGenericFieldType.java
new file mode 100644
index 0000000000000..c817bfc754ba0
--- /dev/null
+++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_field_type/BadRecordGenericFieldType.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2002-2016 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.tooling.procedure.procedures.invalid.bad_record_field_type;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Path;
+import org.neo4j.graphdb.Relationship;
+
+public class BadRecordGenericFieldType
+{
+
+ public Map wrongType1;
+ public List wrongType2;
+ public List>> wrongType3;
+ public List okType1;
+ public List okType2;
+ public List okType4;
+ public List okType6;
+ public List okType7;
+ public List okType9;
+ public List okType10;
+ public List okType11;
+ public List