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 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 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 annotations, RoundEnvironment roundEnv ) + { + + processElements( roundEnv ); + if ( roundEnv.processingOver() ) + { + duplicationPredicate.apply( visitedProcedures ).forEach( messagePrinter::print ); + } + return false; + } + + private void processElements( RoundEnvironment roundEnv ) + { + Set 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 annotations, RoundEnvironment roundEnv ) + { + processElements( roundEnv ); + if ( roundEnv.processingOver() ) + { + duplicationPredicate.apply( visitedFunctions ).forEach( messagePrinter::print ); + } + return false; + } + + private void processElements( RoundEnvironment roundEnv ) + { + Set 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 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 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 annotationType; + + public AnnotationTypeVisitor( Class 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 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 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 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 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 okType12; + public Map okType13; + public HashMap okType14; + public ArrayList okType15; + public ArrayList okType16; +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_field_type/BadRecordGenericFieldTypeSproc.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_field_type/BadRecordGenericFieldTypeSproc.java new file mode 100644 index 0000000000000..69af64e81c9fb --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_field_type/BadRecordGenericFieldTypeSproc.java @@ -0,0 +1,34 @@ +/* + * 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.stream.Stream; + +import org.neo4j.procedure.Procedure; + +public class BadRecordGenericFieldTypeSproc +{ + + @Procedure + public Stream doSomething() + { + return Stream.empty(); + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_field_type/BadRecordSimpleFieldType.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_field_type/BadRecordSimpleFieldType.java new file mode 100644 index 0000000000000..66047f6cace51 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_field_type/BadRecordSimpleFieldType.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.procedures.invalid.bad_record_field_type; + +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Path; +import org.neo4j.graphdb.Relationship; + +public class BadRecordSimpleFieldType +{ + + public Integer wrongType; + public String okType1; + public Long okType2; + public long okType3; + public Double okType4; + public double okType5; + public Number okType6; + public Boolean okType7; + public boolean okType8; + public Path okType9; + public Node okType10; + public Relationship okType11; + public Object okType12; +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_field_type/BadRecordSimpleFieldTypeSproc.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_field_type/BadRecordSimpleFieldTypeSproc.java new file mode 100644 index 0000000000000..b3bddef1926d0 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_field_type/BadRecordSimpleFieldTypeSproc.java @@ -0,0 +1,34 @@ +/* + * 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.stream.Stream; + +import org.neo4j.procedure.Procedure; + +public class BadRecordSimpleFieldTypeSproc +{ + + @Procedure + public Stream doSomething() + { + return Stream.empty(); + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_type/BadRecord.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_type/BadRecord.java new file mode 100644 index 0000000000000..dd846afe67a75 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_type/BadRecord.java @@ -0,0 +1,34 @@ +/* + * 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_type; + +public class BadRecord +{ + + private static final int DEFAULT_AGE = 42; + private final String label; /* nonstatic fields should be public */ + private final int age; + + public BadRecord( String label, int age ) + { + this.label = label; + this.age = age < 0 ? DEFAULT_AGE : age; + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_type/BadRecordTypeSproc.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_type/BadRecordTypeSproc.java new file mode 100644 index 0000000000000..3dac2e0c650b7 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_record_type/BadRecordTypeSproc.java @@ -0,0 +1,34 @@ +/* + * 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_type; + +import java.util.stream.Stream; + +import org.neo4j.procedure.Procedure; + +public class BadRecordTypeSproc +{ + + @Procedure + public Stream doIt() + { + return Stream.of( new BadRecord( "bad", 42 ) ); + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_return_type/BadReturnTypeSproc.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_return_type/BadReturnTypeSproc.java new file mode 100644 index 0000000000000..8e9c1ad75aa26 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_return_type/BadReturnTypeSproc.java @@ -0,0 +1,43 @@ +/* + * 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_return_type; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.procedure.Context; +import org.neo4j.procedure.Name; +import org.neo4j.procedure.Procedure; + +public class BadReturnTypeSproc +{ + + @Context + public GraphDatabaseService db; + + @Procedure + public Long niceSproc( @Name( "foo" ) String parameter ) + { + return 42L; + } + + @Procedure + public void niceSproc2( @Name( "foo" ) String parameter ) + { + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_return_type/BadReturnTypeUserFunction.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_return_type/BadReturnTypeUserFunction.java new file mode 100644 index 0000000000000..93e4c5bb2ca06 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/bad_return_type/BadReturnTypeUserFunction.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.procedures.invalid.bad_return_type; + +import java.util.stream.Stream; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.procedure.Context; +import org.neo4j.procedure.Name; +import org.neo4j.procedure.UserFunction; + +public class BadReturnTypeUserFunction +{ + + @Context + public GraphDatabaseService db; + + @UserFunction + public Stream wrongReturnTypeFunction( @Name( "foo" ) String parameter ) + { + return Stream.empty(); + } + + @UserFunction + public Long niceFunction( @Name( "foo" ) String parameter ) + { + return 3L; + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/conflicting_mode/ConflictingMode.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/conflicting_mode/ConflictingMode.java new file mode 100644 index 0000000000000..4a7b7d92ba032 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/conflicting_mode/ConflictingMode.java @@ -0,0 +1,34 @@ +/* + * 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.conflicting_mode; + +import org.neo4j.procedure.Mode; +import org.neo4j.procedure.PerformsWrites; +import org.neo4j.procedure.Procedure; + +public class ConflictingMode +{ + @Procedure( mode = Mode.DBMS ) + @PerformsWrites + public void wrongMode() + { + + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/duplicated/Sproc1.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/duplicated/Sproc1.java new file mode 100644 index 0000000000000..2ffc278a0d197 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/duplicated/Sproc1.java @@ -0,0 +1,38 @@ +/* + * 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.duplicated; + +import org.neo4j.procedure.Procedure; + +public class Sproc1 +{ + + @Procedure + public void foobar() + { + + } + + @Procedure + public void foobarbaz() + { + + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/duplicated/Sproc2.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/duplicated/Sproc2.java new file mode 100644 index 0000000000000..579001f61ca34 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/duplicated/Sproc2.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.procedures.invalid.duplicated; + +import org.neo4j.procedure.Procedure; + +public class Sproc2 +{ + + @Procedure + public void foobar() + { + + } + + @Procedure + public void foobarqix() + { + + } + +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/duplicated/UserFunction1.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/duplicated/UserFunction1.java new file mode 100644 index 0000000000000..25166e13c4b87 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/duplicated/UserFunction1.java @@ -0,0 +1,38 @@ +/* + * 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.duplicated; + +import org.neo4j.procedure.UserFunction; + +public class UserFunction1 +{ + + @UserFunction + public String foobar() + { + return "42"; + } + + @UserFunction( name = "my.custom.function" ) + public String foobarbaz() + { + return "42"; + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/duplicated/UserFunction2.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/duplicated/UserFunction2.java new file mode 100644 index 0000000000000..62a405ebf1b2d --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/duplicated/UserFunction2.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.procedures.invalid.duplicated; + +import org.neo4j.procedure.UserFunction; + +public class UserFunction2 +{ + + @UserFunction + public String foobar() + { + return "42"; + } + + @UserFunction + public String foobarbaz() + { + return "42"; + } + +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/missing_constructor/MissingConstructorProcedure.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/missing_constructor/MissingConstructorProcedure.java new file mode 100644 index 0000000000000..068b841fdb3f5 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/missing_constructor/MissingConstructorProcedure.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.missing_constructor; + +import org.neo4j.procedure.Procedure; + +public class MissingConstructorProcedure +{ + // should be no-arg + public MissingConstructorProcedure( String oopsAParameter ) + { + } + + // should be public + private MissingConstructorProcedure() + { + + } + + @Procedure + public void foobar() + { + + } + + @Procedure + public void foobarqix() + { + + } + +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/missing_name/MissingNameSproc.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/missing_name/MissingNameSproc.java new file mode 100644 index 0000000000000..a3c51f49a32d4 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/missing_name/MissingNameSproc.java @@ -0,0 +1,44 @@ +/* + * 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.missing_name; + +import java.util.stream.Stream; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.procedure.Context; +import org.neo4j.procedure.Procedure; + +public class MissingNameSproc +{ + + @Context + public GraphDatabaseService db; + + @Procedure + public Stream niceSproc( String parameter, String otherParam ) + { + return Stream.empty(); + } + + public static class GoodRecord + { + public long age; + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/missing_name/MissingNameUserFunction.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/missing_name/MissingNameUserFunction.java new file mode 100644 index 0000000000000..613f3651e8ad4 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/invalid/missing_name/MissingNameUserFunction.java @@ -0,0 +1,33 @@ +/* + * 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.missing_name; + +import org.neo4j.procedure.UserFunction; + +public class MissingNameUserFunction +{ + + @UserFunction + public String niceFunction( String parameter, String otherParam ) + { + return "42"; + } + +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/valid/Procedures.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/valid/Procedures.java new file mode 100644 index 0000000000000..15f0e1f849ff3 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/valid/Procedures.java @@ -0,0 +1,217 @@ +/* + * 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.valid; + +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +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 Procedures +{ + + @Procedure + public Stream theAnswer() + { + return Stream.of( new Records.LongWrapper( 42L ) ); + } + + @Procedure + public void simpleInput00() + { + } + + @Procedure + public void simpleInput01( @Name( "foo" ) String input ) + { + } + + @Procedure + public void simpleInput02( @Name( "foo" ) long input ) + { + } + + @Procedure + public void simpleInput03( @Name( "foo" ) Long input ) + { + } + + @Procedure + public void simpleInput04( @Name( "foo" ) Number input ) + { + } + + @Procedure + public void simpleInput05( @Name( "foo" ) Boolean input ) + { + } + + @Procedure + public void simpleInput06( @Name( "foo" ) boolean input ) + { + } + + @Procedure + public void simpleInput07( @Name( "foo" ) Object input ) + { + } + + @Procedure + public void simpleInput08( @Name( "foo" ) Node input ) + { + } + + @Procedure + public void simpleInput09( @Name( "foo" ) Path input ) + { + } + + @Procedure + public void simpleInput10( @Name( "foo" ) Relationship input ) + { + } + + @Procedure + public Stream simpleInput11( @Name( "foo" ) String input ) + { + return Stream.of( new Records.SimpleTypesWrapper() ); + } + + @Procedure + public Stream simpleInput12( @Name( "foo" ) long input ) + { + return Stream.of( new Records.SimpleTypesWrapper() ); + } + + @Procedure + public Stream simpleInput13( @Name( "foo" ) Long input ) + { + return Stream.of( new Records.SimpleTypesWrapper() ); + } + + @Procedure + public Stream simpleInput14( @Name( "foo" ) Number input ) + { + return Stream.of( new Records.SimpleTypesWrapper() ); + } + + @Procedure + public Stream simpleInput15( @Name( "foo" ) Boolean input ) + { + return Stream.of( new Records.SimpleTypesWrapper() ); + } + + @Procedure + public Stream simpleInput16( @Name( "foo" ) boolean input ) + { + return Stream.of( new Records.SimpleTypesWrapper() ); + } + + @Procedure + public Stream simpleInput17( @Name( "foo" ) Object input ) + { + return Stream.of( new Records.SimpleTypesWrapper() ); + } + + @Procedure + public Stream simpleInput18( @Name( "foo" ) Node input ) + { + return Stream.of( new Records.SimpleTypesWrapper() ); + } + + @Procedure + public Stream simpleInput19( @Name( "foo" ) Path input ) + { + return Stream.of( new Records.SimpleTypesWrapper() ); + } + + @Procedure + public Stream simpleInput20( @Name( "foo" ) Relationship input ) + { + return Stream.of( new Records.SimpleTypesWrapper() ); + } + + @Procedure + public Stream simpleInput21() + { + return Stream.of( new Records.SimpleTypesWrapper() ); + } + + @Procedure + public void genericInput01( @Name( "foo" ) List input ) + { + } + + @Procedure + public void genericInput02( @Name( "foo" ) List> input ) + { + } + + @Procedure + public void genericInput03( @Name( "foo" ) Map> input ) + { + } + + @Procedure + public void genericInput04( @Name( "foo" ) Map input ) + { + } + + @Procedure + public void genericInput05( @Name( "foo" ) Map>>>>> input ) + { + } + + @Procedure + public Stream genericInput06( @Name( "foo" ) List input ) + { + return Stream.of( new Records.GenericTypesWrapper() ); + } + + @Procedure + public Stream genericInput07( @Name( "foo" ) List> input ) + { + return Stream.of( new Records.GenericTypesWrapper() ); + } + + @Procedure + public Stream genericInput08( @Name( "foo" ) Map> input ) + { + return Stream.of( new Records.GenericTypesWrapper() ); + } + + @Procedure + public Stream genericInput09( @Name( "foo" ) Map input ) + { + return Stream.of( new Records.GenericTypesWrapper() ); + } + + @Procedure + public Stream genericInput10( + @Name( "foo" ) Map>>>>> input ) + { + return Stream.of( new Records.GenericTypesWrapper() ); + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/valid/Records.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/valid/Records.java new file mode 100644 index 0000000000000..55950233b4edc --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/valid/Records.java @@ -0,0 +1,77 @@ +/* + * 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.valid; + +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 Records +{ + + public static class LongWrapper + { + public final Long value; + + public LongWrapper( Long value ) + { + this.value = value; + } + } + + public static class SimpleTypesWrapper + { + public String field01 = "string"; + public long field02 = 2; + public Long field03 = 3L; + public Number field04 = 4.0; + public Boolean field05 = true; + public boolean field06 = true; + public Object field07; + public Node field08; + public Path field09; + public Relationship field10; + } + + public static class GenericTypesWrapper + { + public List field01; + public List field03; + public List field04; + public List field05; + public List field07; + public List field08; + public List field09; + public List field10; + public Map field11; + public Map field13; + public Map field14; + public Map field15; + public Map field17; + public Map field18; + public Map field19; + public Map field20; + public List> field21; + public List> field22; + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/valid/UserFunctions.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/valid/UserFunctions.java new file mode 100644 index 0000000000000..c92031045ce72 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/procedures/valid/UserFunctions.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.procedures.valid; + +import java.util.List; +import java.util.Map; + +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 UserFunctions +{ + + @UserFunction + public String simpleInput00() + { + return "42"; + } + + @UserFunction + public String simpleInput01( @Name( "foo" ) String input ) + { + return "42"; + } + + @UserFunction + public String simpleInput02( @Name( "foo" ) long input ) + { + return "42"; + } + + @UserFunction + public String simpleInput03( @Name( "foo" ) Long input ) + { + return "42"; + } + + @UserFunction + public String simpleInput04( @Name( "foo" ) Number input ) + { + return "42"; + } + + @UserFunction + public String simpleInput05( @Name( "foo" ) Boolean input ) + { + return "42"; + } + + @UserFunction + public String simpleInput06( @Name( "foo" ) boolean input ) + { + return "42"; + } + + @UserFunction + public String simpleInput07( @Name( "foo" ) Object input ) + { + return "42"; + } + + @UserFunction + public String simpleInput08( @Name( "foo" ) Node input ) + { + return "42"; + } + + @UserFunction + public String simpleInput09( @Name( "foo" ) Path input ) + { + return "42"; + } + + @UserFunction + public String simpleInput10( @Name( "foo" ) Relationship input ) + { + return "42"; + } + + @UserFunction + public String genericInput01( @Name( "foo" ) List input ) + { + return "42"; + } + + @UserFunction + public String genericInput02( @Name( "foo" ) List> input ) + { + return "42"; + } + + @UserFunction + public String genericInput03( @Name( "foo" ) Map> input ) + { + return "42"; + } + + @UserFunction + public String genericInput04( @Name( "foo" ) Map input ) + { + return "42"; + } + + @UserFunction + public String genericInput05( @Name( "foo" ) Map>>>>> input ) + { + return "42"; + } + +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/testutils/ElementTestUtils.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/testutils/ElementTestUtils.java new file mode 100644 index 0000000000000..ca41acb24db92 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/testutils/ElementTestUtils.java @@ -0,0 +1,69 @@ +/* + * 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.testutils; + +import com.google.testing.compile.CompilationRule; + +import java.util.stream.Stream; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; + +import static javax.lang.model.util.ElementFilter.fieldsIn; + +public class ElementTestUtils +{ + + private final Elements elements; + private final Types types; + private final TypeMirrorTestUtils typeMirrorTestUtils; + + public ElementTestUtils( CompilationRule rule ) + { + this( rule.getElements(), rule.getTypes(), new TypeMirrorTestUtils( rule ) ); + } + + private ElementTestUtils( Elements elements, Types types, TypeMirrorTestUtils typeMirrorTestUtils ) + { + this.elements = elements; + this.types = types; + this.typeMirrorTestUtils = typeMirrorTestUtils; + } + + public Stream getFields( Class type ) + { + TypeElement procedure = elements.getTypeElement( type.getName() ); + + return fieldsIn( procedure.getEnclosedElements() ).stream(); + } + + public Element findMethodElement( Class type, String methodName ) + { + TypeMirror mirror = typeMirrorTestUtils.typeOf( type ); + return ElementFilter.methodsIn( types.asElement( mirror ).getEnclosedElements() ).stream() + .filter( method -> method.getSimpleName().contentEquals( methodName ) ).findFirst().orElseThrow( + () -> new AssertionError( + String.format( "Could not find method %s of class %s", methodName, type.getName() ) ) ); + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/testutils/JavaFileObjectUtils.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/testutils/JavaFileObjectUtils.java new file mode 100644 index 0000000000000..d480ffa5590ca --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/testutils/JavaFileObjectUtils.java @@ -0,0 +1,77 @@ +/* + * 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.testutils; + +import com.google.testing.compile.JavaFileObjects; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Properties; +import javax.tools.JavaFileObject; + +import static org.assertj.core.api.Assertions.assertThat; + +public enum JavaFileObjectUtils +{ + INSTANCE; + + private final String baseDirectory; + + JavaFileObjectUtils() + { + Properties properties = loadProperties( "/procedures.properties" ); + baseDirectory = properties.getProperty( "base_directory" ); + assertThat( new File( baseDirectory ) ).exists(); + } + + public JavaFileObject procedureSource( String relativePath ) + { + return JavaFileObjects.forResource( resolveUrl( relativePath ) ); + } + + private final Properties loadProperties( String name ) + { + try ( InputStream paths = this.getClass().getResourceAsStream( name ) ) + { + Properties properties = new Properties(); + properties.load( paths ); + return properties; + } + catch ( IOException e ) + { + throw new RuntimeException( e ); + } + } + + private URL resolveUrl( String relativePath ) + { + try + { + return new File( baseDirectory, relativePath ).toURI().toURL(); + } + catch ( MalformedURLException e ) + { + throw new RuntimeException( e.getMessage(), e ); + } + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/testutils/TypeMirrorTestUtils.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/testutils/TypeMirrorTestUtils.java new file mode 100644 index 0000000000000..3e4551703bd75 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/testutils/TypeMirrorTestUtils.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.testutils; + +import com.google.testing.compile.CompilationRule; +import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils; + +import java.util.stream.Stream; +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 static java.util.Arrays.stream; +import static java.util.stream.Collectors.toList; + +public class TypeMirrorTestUtils +{ + + private final Types types; + private final Elements elements; + private final TypeMirrorUtils typeMirrors; + + public TypeMirrorTestUtils( CompilationRule rule ) + { + this( rule.getTypes(), rule.getElements(), new TypeMirrorUtils( rule.getTypes(), rule.getElements() ) ); + } + + private TypeMirrorTestUtils( Types types, Elements elements, TypeMirrorUtils typeMirrors ) + { + this.types = types; + this.elements = elements; + this.typeMirrors = typeMirrors; + } + + public TypeMirror typeOf( Class type, Class... parameterTypes ) + { + return types.getDeclaredType( elements.getTypeElement( type.getName() ), typesOf( parameterTypes ) ); + } + + public TypeMirror typeOf( Class type, TypeMirror... parameterTypes ) + { + return types.getDeclaredType( elements.getTypeElement( type.getName() ), parameterTypes ); + } + + public PrimitiveType typeOf( TypeKind kind ) + { + return typeMirrors.primitive( kind ); + } + + public TypeMirror typeOf( Class type ) + { + return typeMirrors.typeMirror( type ); + } + + private TypeMirror[] typesOf( Class... parameterTypes ) + { + Stream mirrorStream = stream( parameterTypes ).map( this::typeOf ); + return mirrorStream.collect( toList() ).toArray( new TypeMirror[parameterTypes.length] ); + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/AllowedTypesValidatorTest.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/AllowedTypesValidatorTest.java new file mode 100644 index 0000000000000..26c08de2afad7 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/AllowedTypesValidatorTest.java @@ -0,0 +1,180 @@ +/* + * 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 com.google.testing.compile.CompilationRule; +import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils; +import org.neo4j.tooling.procedure.testutils.TypeMirrorTestUtils; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +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 javax.lang.model.type.TypeKind.BOOLEAN; +import static javax.lang.model.type.TypeKind.DOUBLE; +import static javax.lang.model.type.TypeKind.LONG; +import static org.assertj.core.api.Assertions.assertThat; + +public class AllowedTypesValidatorTest +{ + + @Rule + public CompilationRule compilation = new CompilationRule(); + private TypeMirrorTestUtils typeMirrorTestUtils; + private Predicate validator; + + @Before + public void prepare() + { + Types types = compilation.getTypes(); + Elements elements = compilation.getElements(); + TypeMirrorUtils typeMirrors = new TypeMirrorUtils( types, elements ); + + typeMirrorTestUtils = new TypeMirrorTestUtils( compilation ); + validator = new AllowedTypesValidator( typeMirrors, types ); + } + + @Test + public void unsupported_simple_type_is_invalid() + { + assertThat( validator.test( typeMirrorTestUtils.typeOf( CharSequence.class ) ) ).isFalse(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Thread.class ) ) ).isFalse(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Character.class ) ) ).isFalse(); + } + + @Test + public void supported_simple_type_is_valid() + { + assertThat( validator.test( typeMirrorTestUtils.typeOf( BOOLEAN ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( LONG ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( DOUBLE ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Boolean.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Long.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Double.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( String.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Number.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Object.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Node.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Relationship.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Path.class ) ) ).isTrue(); + } + + @Test + public void supported_list_type_is_valid() + { + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, Boolean.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, Long.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, Double.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, String.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, Number.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, Object.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, Node.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, Relationship.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, Path.class ) ) ).isTrue(); + } + + @Test + public void unsupported_list_type_is_invalid() + { + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, CharSequence.class ) ) ).isFalse(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, Thread.class ) ) ).isFalse(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, Character.class ) ) ).isFalse(); + } + + @Test + public void supported_recursive_list_type_is_valid() + { + assertThat( validator.test( typeMirrorTestUtils + .typeOf( List.class, typeMirrorTestUtils.typeOf( List.class, Boolean.class ) ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, + typeMirrorTestUtils.typeOf( List.class, typeMirrorTestUtils.typeOf( List.class, Object.class ) ) ) ) ) + .isTrue(); + } + + @Test + public void unsupported_recursive_list_type_is_invalid() + { + assertThat( validator.test( typeMirrorTestUtils + .typeOf( List.class, typeMirrorTestUtils.typeOf( List.class, CharSequence.class ) ) ) ).isFalse(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, + typeMirrorTestUtils.typeOf( List.class, typeMirrorTestUtils.typeOf( List.class, Thread.class ) ) ) ) ) + .isFalse(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, typeMirrorTestUtils + .typeOf( List.class, typeMirrorTestUtils.typeOf( List.class, Character.class ) ) ) ) ).isFalse(); + } + + @Test + public void supported_map_type_is_valid() + { + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, String.class, Boolean.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, String.class, Long.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, String.class, Double.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, String.class, String.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, String.class, Number.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, String.class, Object.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, String.class, Node.class ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, String.class, Relationship.class ) ) ) + .isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, String.class, Path.class ) ) ).isTrue(); + } + + @Test + public void unsupported_map_type_is_invalid() + { + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, Object.class, Boolean.class ) ) ).isFalse(); + } + + @Test + public void supported_recursive_map_type_is_valid() + { + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, typeMirrorTestUtils.typeOf( String.class ), + typeMirrorTestUtils.typeOf( Map.class, String.class, Boolean.class ) ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, typeMirrorTestUtils.typeOf( String.class ), + typeMirrorTestUtils.typeOf( Map.class, typeMirrorTestUtils.typeOf( String.class ), + typeMirrorTestUtils.typeOf( Map.class, String.class, Boolean.class ) ) ) ) ).isTrue(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, typeMirrorTestUtils + .typeOf( List.class, typeMirrorTestUtils.typeOf( Map.class, String.class, Boolean.class ) ) ) ) ) + .isTrue(); + } + + @Test + public void unsupported_recursive_map_type_is_invalid() + { + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, typeMirrorTestUtils.typeOf( String.class ), + typeMirrorTestUtils.typeOf( Map.class, String.class, Thread.class ) ) ) ).isFalse(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( Map.class, typeMirrorTestUtils.typeOf( String.class ), + typeMirrorTestUtils.typeOf( Map.class, typeMirrorTestUtils.typeOf( String.class ), + typeMirrorTestUtils.typeOf( Map.class, String.class, CharSequence.class ) ) ) ) ).isFalse(); + assertThat( validator.test( typeMirrorTestUtils.typeOf( List.class, typeMirrorTestUtils + .typeOf( List.class, typeMirrorTestUtils.typeOf( Map.class, String.class, Character.class ) ) ) ) ) + .isFalse(); + } + +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/DuplicatedProcedureValidatorTest.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/DuplicatedProcedureValidatorTest.java new file mode 100644 index 0000000000000..7e96fb850fafc --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/DuplicatedProcedureValidatorTest.java @@ -0,0 +1,128 @@ +/* + * 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 com.google.testing.compile.CompilationRule; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.util.Collection; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; +import javax.tools.Diagnostic; + +import org.neo4j.procedure.Procedure; +import org.neo4j.tooling.procedure.ProcedureProcessor; +import org.neo4j.tooling.procedure.messages.CompilationMessage; +import org.neo4j.tooling.procedure.validators.examples.DefaultProcedureA; +import org.neo4j.tooling.procedure.validators.examples.DefaultProcedureB; +import org.neo4j.tooling.procedure.validators.examples.OverriddenProcedureB; +import org.neo4j.tooling.procedure.validators.examples.override.OverriddenProcedureA; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.groups.Tuple.tuple; + +public class DuplicatedProcedureValidatorTest +{ + + @Rule + public CompilationRule compilation = new CompilationRule(); + + private Elements elements; + private Function,Stream> validator; + + @Before + public void prepare() + { + elements = compilation.getElements(); + validator = new DuplicatedProcedureValidator<>( elements, Procedure.class, ProcedureProcessor::getCustomName ); + } + + @Test + public void detects_duplicate_procedure_with_default_names() + { + Element procedureA = procedureMethod( DefaultProcedureA.class.getName() ); + Element procedureB = procedureMethod( DefaultProcedureB.class.getName() ); + Collection duplicates = asList( procedureA, procedureB ); + + Stream errors = validator.apply( duplicates ); + + String procedureName = "org.neo4j.tooling.procedure.validators.examples.procedure"; + assertThat( errors ).extracting( CompilationMessage::getCategory, CompilationMessage::getElement, + CompilationMessage::getContents ).containsExactlyInAnyOrder( tuple( Diagnostic.Kind.ERROR, procedureA, + "Procedure|function name <" + procedureName + "> is already defined 2 times. It should be defined " + + "only once!" ), tuple( Diagnostic.Kind.ERROR, procedureB, + "Procedure|function name <" + procedureName + + "> is already defined 2 times. It should be defined only once!" ) ); + } + + @Test + public void detects_duplicate_procedure_with_overridden_names() + { + Element procedureA = procedureMethod( OverriddenProcedureA.class.getName() ); + Element procedureB = procedureMethod( OverriddenProcedureB.class.getName() ); + Collection duplicates = asList( procedureA, procedureB ); + + Stream errors = validator.apply( duplicates ); + + assertThat( errors ).extracting( CompilationMessage::getCategory, CompilationMessage::getElement, + CompilationMessage::getContents ).containsExactlyInAnyOrder( tuple( Diagnostic.Kind.ERROR, procedureA, + "Procedure|function name is already defined 2 times. It should be defined only once!" ), + tuple( Diagnostic.Kind.ERROR, procedureB, + "Procedure|function name is already defined 2 times. It should be defined only " + + "once!" ) ); + } + + @Test + public void does_not_detect_duplicates_if_duplicate_procedure_has_custom_name() + { + Collection duplicates = asList( procedureMethod( DefaultProcedureA.class.getName() ), + procedureMethod( OverriddenProcedureB.class.getName() ) ); + + Stream errors = validator.apply( duplicates ); + + assertThat( errors ).isEmpty(); + } + + private Element procedureMethod( String name ) + { + TypeElement typeElement = elements.getTypeElement( name ); + Collection procedures = findProcedures( typeElement ); + if ( procedures.size() != 1 ) + { + throw new AssertionError( "Test procedure class should only have 1 defined procedure" ); + } + return procedures.iterator().next(); + } + + private Collection findProcedures( TypeElement typeElement ) + { + return typeElement.getEnclosedElements().stream() + .filter( element -> element.getAnnotation( Procedure.class ) != null ) + .collect( Collectors.toList() ); + } + +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/examples/DefaultProcedureA.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/examples/DefaultProcedureA.java new file mode 100644 index 0000000000000..bc012b6cee5aa --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/examples/DefaultProcedureA.java @@ -0,0 +1,31 @@ +/* + * 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.examples; + +import org.neo4j.procedure.Procedure; + +public class DefaultProcedureA +{ + @Procedure + public void procedure() + { + + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/examples/DefaultProcedureB.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/examples/DefaultProcedureB.java new file mode 100644 index 0000000000000..06c2a42d86431 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/examples/DefaultProcedureB.java @@ -0,0 +1,31 @@ +/* + * 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.examples; + +import org.neo4j.procedure.Procedure; + +public class DefaultProcedureB +{ + @Procedure + public void procedure() + { + + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/examples/OverriddenProcedureB.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/examples/OverriddenProcedureB.java new file mode 100644 index 0000000000000..6554cfa5b92b2 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/examples/OverriddenProcedureB.java @@ -0,0 +1,32 @@ +/* + * 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.examples; + +import org.neo4j.procedure.Procedure; + +public class OverriddenProcedureB +{ + + @Procedure( value = "override" ) + public void procedure() + { + + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/examples/override/OverriddenProcedureA.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/examples/override/OverriddenProcedureA.java new file mode 100644 index 0000000000000..436588d9698f9 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/validators/examples/override/OverriddenProcedureA.java @@ -0,0 +1,32 @@ +/* + * 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.examples.override; + +import org.neo4j.procedure.Procedure; + +public class OverriddenProcedureA +{ + + @Procedure( name = "override", value = "name-has-more-priority" ) + public void procedure() + { + + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/ContextFieldVisitorTest.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/ContextFieldVisitorTest.java new file mode 100644 index 0000000000000..23e7f17f6abc3 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/ContextFieldVisitorTest.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 com.google.testing.compile.CompilationRule; +import org.neo4j.tooling.procedure.messages.CompilationMessage; +import org.neo4j.tooling.procedure.testutils.ElementTestUtils; +import org.neo4j.tooling.procedure.visitors.examples.FinalContextMisuse; +import org.neo4j.tooling.procedure.visitors.examples.NonPublicContextMisuse; +import org.neo4j.tooling.procedure.visitors.examples.StaticContextMisuse; +import org.neo4j.tooling.procedure.visitors.examples.UnsupportedInjectedContextTypes; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.util.stream.Stream; +import javax.lang.model.element.ElementVisitor; +import javax.lang.model.element.VariableElement; +import javax.tools.Diagnostic; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +public class ContextFieldVisitorTest +{ + + @Rule + public CompilationRule compilationRule = new CompilationRule(); + private ElementTestUtils elementTestUtils; + private ElementVisitor,Void> contextFieldVisitor; + + @Before + public void prepare() + { + elementTestUtils = new ElementTestUtils( compilationRule ); + contextFieldVisitor = + new ContextFieldVisitor( compilationRule.getTypes(), compilationRule.getElements(), false ); + } + + @Test + public void rejects_non_public_context_fields() + { + Stream fields = elementTestUtils.getFields( NonPublicContextMisuse.class ); + + Stream result = fields.flatMap( contextFieldVisitor::visit ); + + assertThat( result ).extracting( CompilationMessage::getCategory, CompilationMessage::getContents ) + .containsExactly( tuple( Diagnostic.Kind.ERROR, + "@org.neo4j.procedure.Context usage error: field NonPublicContextMisuse#arithm should be public, " + + "non-static and non-final" ) ); + } + + @Test + public void rejects_static_context_fields() + { + Stream fields = elementTestUtils.getFields( StaticContextMisuse.class ); + + Stream result = fields.flatMap( contextFieldVisitor::visit ); + + assertThat( result ).extracting( CompilationMessage::getCategory, CompilationMessage::getContents ) + .containsExactly( tuple( Diagnostic.Kind.ERROR, + "@org.neo4j.procedure.Context usage error: field StaticContextMisuse#db should be public, non-static " + + "and non-final" ) ); + } + + @Test + public void rejects_final_context_fields() + { + Stream fields = elementTestUtils.getFields( FinalContextMisuse.class ); + + Stream result = fields.flatMap( contextFieldVisitor::visit ); + + assertThat( result ).extracting( CompilationMessage::getCategory, CompilationMessage::getContents ) + .containsExactly( tuple( Diagnostic.Kind.ERROR, + "@org.neo4j.procedure.Context usage error: field FinalContextMisuse#graphDatabaseService should be " + + "public, non-static and non-final" ) ); + } + + @Test + public void warns_against_unsupported_injected_types_when_warnings_enabled() + { + Stream fields = elementTestUtils.getFields( UnsupportedInjectedContextTypes.class ); + + Stream result = fields.flatMap( contextFieldVisitor::visit ); + + assertThat( result ).extracting( CompilationMessage::getCategory, CompilationMessage::getContents ) + .containsExactlyInAnyOrder( tuple( Diagnostic.Kind.WARNING, + "@org.neo4j.procedure.Context usage warning: found type: , expected one of: , " ), + tuple( Diagnostic.Kind.WARNING, + "@org.neo4j.procedure.Context usage warning: found type: , expected one of: , " ) ); + } + + @Test + public void does_not_warn_against_unsupported_injected_types_when_warnings_disabled() + { + ContextFieldVisitor contextFieldVisitor = + new ContextFieldVisitor( compilationRule.getTypes(), compilationRule.getElements(), true ); + Stream fields = elementTestUtils.getFields( UnsupportedInjectedContextTypes.class ); + + Stream result = fields.flatMap( contextFieldVisitor::visit ); + + assertThat( result ).isEmpty(); + } + +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/FieldVisitorTest.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/FieldVisitorTest.java new file mode 100644 index 0000000000000..f951ab158b0a1 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/FieldVisitorTest.java @@ -0,0 +1,77 @@ +/* + * 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 com.google.testing.compile.CompilationRule; +import org.neo4j.tooling.procedure.messages.CompilationMessage; +import org.neo4j.tooling.procedure.testutils.ElementTestUtils; +import org.neo4j.tooling.procedure.visitors.examples.GoodContextUse; +import org.neo4j.tooling.procedure.visitors.examples.StaticNonContextMisuse; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.util.stream.Stream; +import javax.lang.model.element.ElementVisitor; +import javax.lang.model.element.VariableElement; +import javax.tools.Diagnostic; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +public class FieldVisitorTest +{ + + @Rule + public CompilationRule compilationRule = new CompilationRule(); + private ElementVisitor,Void> fieldVisitor; + private ElementTestUtils elementTestUtils; + + @Before + public void prepare() + { + elementTestUtils = new ElementTestUtils( compilationRule ); + fieldVisitor = new FieldVisitor( compilationRule.getTypes(), compilationRule.getElements(), false ); + } + + @Test + public void validates_visibility_of_fields() throws Exception + { + Stream fields = elementTestUtils.getFields( GoodContextUse.class ); + + Stream result = fields.flatMap( fieldVisitor::visit ); + + assertThat( result ).isEmpty(); + } + + @Test + public void rejects_non_static_non_context_fields() + { + Stream fields = elementTestUtils.getFields( StaticNonContextMisuse.class ); + + Stream result = fields.flatMap( fieldVisitor::visit ); + + assertThat( result ).extracting( CompilationMessage::getCategory, CompilationMessage::getContents ) + .containsExactly( + tuple( Diagnostic.Kind.ERROR, "Field StaticNonContextMisuse#value should be static" ) ); + } + +} + diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/ParameterTypeVisitorTest.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/ParameterTypeVisitorTest.java new file mode 100644 index 0000000000000..af723b17b9122 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/ParameterTypeVisitorTest.java @@ -0,0 +1,61 @@ +/* + * 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 com.google.testing.compile.CompilationRule; +import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils; +import org.neo4j.tooling.procedure.testutils.TypeMirrorTestUtils; +import org.junit.Before; +import org.junit.Rule; + +import javax.lang.model.type.TypeVisitor; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; + +public class ParameterTypeVisitorTest extends TypeValidationTestSuite +{ + + @Rule + public CompilationRule compilationRule = new CompilationRule(); + private Types types; + private TypeMirrorUtils typeMirrorUtils; + private TypeMirrorTestUtils typeMirrorTestUtils; + + @Before + public void prepare() + { + Elements elements = compilationRule.getElements(); + types = compilationRule.getTypes(); + typeMirrorUtils = new TypeMirrorUtils( types, elements ); + typeMirrorTestUtils = new TypeMirrorTestUtils( compilationRule ); + } + + @Override + protected TypeVisitor visitor() + { + return new ParameterTypeVisitor( types, typeMirrorUtils ); + } + + @Override + protected TypeMirrorTestUtils typeMirrorTestUtils() + { + return typeMirrorTestUtils; + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/PerformsWriteMethodVisitorTest.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/PerformsWriteMethodVisitorTest.java new file mode 100644 index 0000000000000..676655ee227cc --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/PerformsWriteMethodVisitorTest.java @@ -0,0 +1,86 @@ +/* + * 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 com.google.testing.compile.CompilationRule; +import org.neo4j.tooling.procedure.messages.CompilationMessage; +import org.neo4j.tooling.procedure.testutils.ElementTestUtils; +import org.neo4j.tooling.procedure.visitors.examples.PerformsWriteProcedures; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.util.stream.Stream; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementVisitor; +import javax.tools.Diagnostic; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.groups.Tuple.tuple; + +public class PerformsWriteMethodVisitorTest +{ + @Rule + public CompilationRule compilationRule = new CompilationRule(); + + private ElementVisitor,Void> visitor = new PerformsWriteMethodVisitor(); + private ElementTestUtils elementTestUtils; + + @Before + public void prepare() + { + elementTestUtils = new ElementTestUtils( compilationRule ); + } + + @Test + public void rejects_non_procedure_methods() + { + Element element = + elementTestUtils.findMethodElement( PerformsWriteProcedures.class, "missingProcedureAnnotation" ); + + Stream errors = visitor.visit( element ); + + assertThat( errors ).hasSize( 1 ).extracting( CompilationMessage::getCategory, CompilationMessage::getElement, + CompilationMessage::getContents ).contains( tuple( Diagnostic.Kind.ERROR, element, + "@PerformsWrites usage error: missing @Procedure annotation on method" ) ); + } + + @Test + public void rejects_conflicted_mode_usage() + { + Element element = elementTestUtils.findMethodElement( PerformsWriteProcedures.class, "conflictingMode" ); + + Stream errors = visitor.visit( element ); + + assertThat( errors ).hasSize( 1 ).extracting( CompilationMessage::getCategory, CompilationMessage::getElement, + CompilationMessage::getContents ).contains( tuple( Diagnostic.Kind.ERROR, element, + "@PerformsWrites usage error: cannot use mode other than Mode.DEFAULT" ) ); + } + + @Test + public void validates_regular_procedure() + { + Element element = elementTestUtils.findMethodElement( PerformsWriteProcedures.class, "ok" ); + + Stream errors = visitor.visit( element ); + + assertThat( errors ).isEmpty(); + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/RecordFieldTypeVisitorTest.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/RecordFieldTypeVisitorTest.java new file mode 100644 index 0000000000000..6d370acd15c82 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/RecordFieldTypeVisitorTest.java @@ -0,0 +1,61 @@ +/* + * 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 com.google.testing.compile.CompilationRule; +import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils; +import org.neo4j.tooling.procedure.testutils.TypeMirrorTestUtils; +import org.junit.Before; +import org.junit.Rule; + +import javax.lang.model.type.TypeVisitor; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; + +public class RecordFieldTypeVisitorTest extends TypeValidationTestSuite +{ + + @Rule + public CompilationRule compilationRule = new CompilationRule(); + private Types types; + private TypeMirrorUtils typeMirrorUtils; + private TypeMirrorTestUtils typeMirrorTestUtils; + + @Before + public void prepare() + { + Elements elements = compilationRule.getElements(); + types = compilationRule.getTypes(); + typeMirrorUtils = new TypeMirrorUtils( types, elements ); + typeMirrorTestUtils = new TypeMirrorTestUtils( compilationRule ); + } + + @Override + protected TypeVisitor visitor() + { + return new RecordFieldTypeVisitor( types, typeMirrorUtils ); + } + + @Override + protected TypeMirrorTestUtils typeMirrorTestUtils() + { + return typeMirrorTestUtils; + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/RecordTypeVisitorTest.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/RecordTypeVisitorTest.java new file mode 100644 index 0000000000000..1dd035a90b9c7 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/RecordTypeVisitorTest.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 com.google.testing.compile.CompilationRule; +import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils; +import org.neo4j.tooling.procedure.messages.CompilationMessage; +import org.neo4j.tooling.procedure.testutils.TypeMirrorTestUtils; +import org.neo4j.tooling.procedure.visitors.examples.InvalidRecord; +import org.neo4j.tooling.procedure.visitors.examples.ValidRecord; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.util.stream.Stream; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import javax.tools.Diagnostic; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +public class RecordTypeVisitorTest +{ + + @Rule + public CompilationRule compilation = new CompilationRule(); + private TypeMirrorTestUtils typeMirrorTestUtils; + private RecordTypeVisitor visitor; + + @Before + public void prepare() + { + Types types = compilation.getTypes(); + Elements elements = compilation.getElements(); + TypeMirrorUtils typeMirrors = new TypeMirrorUtils( types, elements ); + + typeMirrorTestUtils = new TypeMirrorTestUtils( compilation ); + visitor = new RecordTypeVisitor( types, typeMirrors ); + } + + @Test + public void validates_supported_record() throws Exception + { + TypeMirror recordStreamType = typeMirrorTestUtils.typeOf( Stream.class, ValidRecord.class ); + + assertThat( visitor.visit( recordStreamType ) ).isEmpty(); + } + + @Test + public void does_not_validate_record_with_nonpublic_fields() throws Exception + { + TypeMirror recordStreamType = typeMirrorTestUtils.typeOf( Stream.class, InvalidRecord.class ); + + assertThat( visitor.visit( recordStreamType ) ).hasSize( 1 ) + .extracting( CompilationMessage::getCategory, CompilationMessage::getContents ).containsExactly( + tuple( Diagnostic.Kind.ERROR, + "Record definition error: field InvalidRecord#foo must" + " be public" ) ); + } + +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/TypeValidationTestSuite.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/TypeValidationTestSuite.java new file mode 100644 index 0000000000000..12b839429dd22 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/TypeValidationTestSuite.java @@ -0,0 +1,107 @@ +/* + * 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.testutils.TypeMirrorTestUtils; +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeVisitor; + +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Path; +import org.neo4j.graphdb.Relationship; + +import static org.assertj.core.api.Assertions.assertThat; + +abstract class TypeValidationTestSuite +{ + + @Test + public void validates_supported_simple_types() + { + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( String.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Number.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Long.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( TypeKind.LONG ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Double.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( TypeKind.DOUBLE ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Boolean.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( TypeKind.BOOLEAN ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Path.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Node.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Relationship.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Object.class ) ) ).isTrue(); + } + + @Test + public void validates_supported_generic_types() + { + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Map.class, String.class, Object.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( HashMap.class, String.class, Object.class ) ) ) + .isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( LinkedHashMap.class, String.class, Object.class ) ) ) + .isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( List.class, String.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( LinkedList.class, Number.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( ArrayList.class, Long.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( List.class, Double.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( List.class, Boolean.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( List.class, Path.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( List.class, Node.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( List.class, Relationship.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( List.class, Object.class ) ) ).isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils() + .typeOf( List.class, typeMirrorTestUtils().typeOf( Map.class, String.class, Object.class ) ) ) ) + .isTrue(); + assertThat( visitor().visit( typeMirrorTestUtils() + .typeOf( List.class, typeMirrorTestUtils().typeOf( LinkedList.class, Long.class ) ) ) ).isTrue(); + } + + @Test + public void rejects_unsupported_types() + { + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Thread.class ) ) ).isFalse(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Map.class, String.class, Integer.class ) ) ) + .isFalse(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Map.class, Integer.class, Object.class ) ) ) + .isFalse(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( Map.class, Integer.class, Integer.class ) ) ) + .isFalse(); + assertThat( visitor().visit( typeMirrorTestUtils().typeOf( List.class, BigDecimal.class ) ) ).isFalse(); + assertThat( visitor().visit( typeMirrorTestUtils() + .typeOf( List.class, typeMirrorTestUtils().typeOf( Map.class, String.class, Integer.class ) ) ) ) + .isFalse(); + assertThat( visitor().visit( typeMirrorTestUtils() + .typeOf( List.class, typeMirrorTestUtils().typeOf( List.class, CharSequence.class ) ) ) ).isFalse(); + } + + protected abstract TypeVisitor visitor(); + + protected abstract TypeMirrorTestUtils typeMirrorTestUtils(); + +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/UserFunctionVisitorTest.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/UserFunctionVisitorTest.java new file mode 100644 index 0000000000000..93da0055f95e1 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/UserFunctionVisitorTest.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.visitors; + +import com.google.testing.compile.CompilationRule; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.util.stream.Stream; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementVisitor; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import javax.tools.Diagnostic; + +import org.neo4j.tooling.procedure.compilerutils.TypeMirrorUtils; +import org.neo4j.tooling.procedure.messages.CompilationMessage; +import org.neo4j.tooling.procedure.testutils.ElementTestUtils; +import org.neo4j.tooling.procedure.visitors.examples.UserFunctionsExamples; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.groups.Tuple.tuple; + +public class UserFunctionVisitorTest +{ + @Rule + public CompilationRule compilationRule = new CompilationRule(); + private ElementTestUtils elementTestUtils; + private ElementVisitor,Void> visitor; + + @Before + public void prepare() + { + Types types = compilationRule.getTypes(); + Elements elements = compilationRule.getElements(); + + elementTestUtils = new ElementTestUtils( compilationRule ); + visitor = new UserFunctionVisitor( types, elements, new TypeMirrorUtils( types, elements ) ); + } + + @Test + public void functions_with_specified_name_cannot_be_in_root_namespace() + { + Element function = elementTestUtils.findMethodElement( UserFunctionsExamples.class, "functionWithName" ); + + Stream errors = visitor.visit( function ); + + assertThat( errors ).hasSize( 1 ).extracting( CompilationMessage::getCategory, CompilationMessage::getElement, + CompilationMessage::getContents ).contains( tuple( Diagnostic.Kind.ERROR, function, + "Function cannot be defined in the root namespace. Valid name example: com.acme.my_function" ) ); + } + + @Test + public void functions_with_specified_value_cannot_be_in_root_namespace() + { + Element function = elementTestUtils.findMethodElement( UserFunctionsExamples.class, "functionWithValue" ); + + Stream errors = visitor.visit( function ); + + assertThat( errors ).hasSize( 1 ).extracting( CompilationMessage::getCategory, CompilationMessage::getElement, + CompilationMessage::getContents ).contains( tuple( Diagnostic.Kind.ERROR, function, + "Function cannot be defined in the root namespace. Valid name example: com.acme.my_function" ) ); + } + + @Test + public void functions_in_non_root_namespace_are_valid() + { + Element function = elementTestUtils.findMethodElement( UserFunctionsExamples.class, "ok" ); + + Stream errors = visitor.visit( function ); + + assertThat( errors ).isEmpty(); + } + + @Test + public void functions_with_unsupported_return_types_are_invalid() + { + Element function = elementTestUtils.findMethodElement( UserFunctionsExamples.class, "wrongReturnType" ); + + Stream errors = visitor.visit( function ); + + assertThat( errors ).hasSize( 1 ).extracting( CompilationMessage::getCategory, CompilationMessage::getElement, + CompilationMessage::getContents ).contains( tuple( Diagnostic.Kind.ERROR, function, + "Unsupported return type of function defined in ." ) ); + } + + @Test + public void functions_with_unsupported_parameter_types_are_invalid() + { + Element function = elementTestUtils.findMethodElement( UserFunctionsExamples.class, "wrongParameterType" ); + + Stream errors = visitor.visit( function ); + + assertThat( errors ).hasSize( 1 ).extracting( CompilationMessage::getCategory, CompilationMessage::getContents ) + .contains( tuple( Diagnostic.Kind.ERROR, + "Unsupported parameter type of procedure|function " + + "UserFunctionsExamples#wrongParameterType" ) ); + } + + @Test + public void functions_with_non_annotated_parameters_are_invalid() + { + Element function = + elementTestUtils.findMethodElement( UserFunctionsExamples.class, "missingParameterAnnotation" ); + + Stream errors = visitor.visit( function ); + + assertThat( errors ).hasSize( 1 ).extracting( CompilationMessage::getCategory, CompilationMessage::getContents ) + .contains( tuple( Diagnostic.Kind.ERROR, + "@org.neo4j.procedure.Name usage error: missing on parameter " ) ); + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/FinalContextMisuse.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/FinalContextMisuse.java new file mode 100644 index 0000000000000..99f33ea2fb4d5 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/FinalContextMisuse.java @@ -0,0 +1,29 @@ +/* + * 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.examples; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.procedure.Context; + +public class FinalContextMisuse +{ + @Context + public final GraphDatabaseService graphDatabaseService = null; +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/GoodContextUse.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/GoodContextUse.java new file mode 100644 index 0000000000000..c791ed3388033 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/GoodContextUse.java @@ -0,0 +1,31 @@ +/* + * 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.examples; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.procedure.Context; + +public class GoodContextUse +{ + private static final Object lock = new Object(); + + @Context + public GraphDatabaseService db; +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/InvalidRecord.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/InvalidRecord.java new file mode 100644 index 0000000000000..6373c5f368635 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/InvalidRecord.java @@ -0,0 +1,27 @@ +/* + * 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.examples; + +public class InvalidRecord +{ + private static String BAR = "bar"; + + String foo = BAR; +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/NonPublicContextMisuse.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/NonPublicContextMisuse.java new file mode 100644 index 0000000000000..d209be785cacf --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/NonPublicContextMisuse.java @@ -0,0 +1,29 @@ +/* + * 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.examples; + +import org.neo4j.logging.Log; +import org.neo4j.procedure.Context; + +public class NonPublicContextMisuse +{ + @Context + Log arithm; +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/PerformsWriteProcedures.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/PerformsWriteProcedures.java new file mode 100644 index 0000000000000..1aaca6f001f09 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/PerformsWriteProcedures.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.visitors.examples; + +import org.neo4j.procedure.Mode; +import org.neo4j.procedure.PerformsWrites; +import org.neo4j.procedure.Procedure; + +public class PerformsWriteProcedures +{ + @PerformsWrites + public void missingProcedureAnnotation() + { + + } + + @Procedure( mode = Mode.READ ) + @PerformsWrites + public void conflictingMode() + { + + } + + @Procedure + @PerformsWrites + public void ok() + { + + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/StaticContextMisuse.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/StaticContextMisuse.java new file mode 100644 index 0000000000000..57fba7c134609 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/StaticContextMisuse.java @@ -0,0 +1,29 @@ +/* + * 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.examples; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.procedure.Context; + +public class StaticContextMisuse +{ + @Context + public static GraphDatabaseService db; +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/StaticNonContextMisuse.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/StaticNonContextMisuse.java new file mode 100644 index 0000000000000..1dfbe7f7488a8 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/StaticNonContextMisuse.java @@ -0,0 +1,25 @@ +/* + * 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.examples; + +public class StaticNonContextMisuse +{ + String value; +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/UnsupportedInjectedContextTypes.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/UnsupportedInjectedContextTypes.java new file mode 100644 index 0000000000000..f74b697ec443e --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/UnsupportedInjectedContextTypes.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.examples; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.kernel.internal.GraphDatabaseAPI; +import org.neo4j.logging.Log; +import org.neo4j.procedure.Context; + +public class UnsupportedInjectedContextTypes +{ + + @Context + public String unsupportedType; + + @Context + public GraphDatabaseAPI notOfficiallySupported; + + @Context + public GraphDatabaseService graphDatabaseService; + + @Context + public Log log; +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/UserFunctionsExamples.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/UserFunctionsExamples.java new file mode 100644 index 0000000000000..c748db105375f --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/UserFunctionsExamples.java @@ -0,0 +1,65 @@ +/* + * 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.examples; + +import org.neo4j.procedure.Name; +import org.neo4j.procedure.UserFunction; + +/* + * see also BadUserFunction in root package + */ +public class UserFunctionsExamples +{ + @UserFunction( name = "in_root_namespace" ) + public String functionWithName() + { + return "42"; + } + + @UserFunction( value = "in_root_namespace_again" ) + public String functionWithValue() + { + return "42"; + } + + @UserFunction( name = "not.in.root.namespace" ) + public String ok() + { + return "42"; + } + + @UserFunction( name = "com.acme.foobar" ) + public void wrongReturnType() + { + + } + + @UserFunction( name = "com.acme.foobar" ) + public String wrongParameterType( @Name( "foo" ) Thread foo ) + { + return "42"; + } + + @UserFunction( name = "com.acme.foobar" ) + public String missingParameterAnnotation( @Name( "foo" ) String foo, String oops ) + { + return "42"; + } +} diff --git a/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/ValidRecord.java b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/ValidRecord.java new file mode 100644 index 0000000000000..56fdb90cee549 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/java/org/neo4j/tooling/procedure/visitors/examples/ValidRecord.java @@ -0,0 +1,27 @@ +/* + * 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.examples; + +public class ValidRecord +{ + private static String BAR = "bar"; + + public String foo = BAR; +} diff --git a/community/procedure-compiler/processor/src/test/resources/procedures.properties b/community/procedure-compiler/processor/src/test/resources/procedures.properties new file mode 100644 index 0000000000000..9d90a93243616 --- /dev/null +++ b/community/procedure-compiler/processor/src/test/resources/procedures.properties @@ -0,0 +1,17 @@ +# +# Copyright 2016-2016 the original author or authors. +# +# 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. +# + +base_directory=${project.basedir}/src/test/java/org/neo4j/tooling/procedure/procedures/