diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/FieldInjections.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/FieldInjections.java index adedc0e6320d5..d455e072f5f14 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/FieldInjections.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/FieldInjections.java @@ -30,11 +30,8 @@ import org.neo4j.kernel.api.exceptions.ProcedureException; import org.neo4j.kernel.api.exceptions.Status; import org.neo4j.kernel.api.proc.CallableProcedure; -import org.neo4j.messages.Messages; import org.neo4j.procedure.Context; -import static org.neo4j.messages.Messages.proc_static_field_annotated_as_context; - /** * Injects annotated fields with appropriate values. */ @@ -98,8 +95,10 @@ public List setters( Class cls ) throws ProcedureException if( field.isAnnotationPresent( Context.class )) { throw new ProcedureException( Status.Procedure.FailedRegistration, - Messages.get( proc_static_field_annotated_as_context, - field.getName(), cls.getSimpleName() ) ); + "The field `%s` in the class named `%s` is annotated as a @Context field,\n" + + "but it is static. @Context fields must be public, non-final and non-static,\n" + + "because they are reset each time a procedure is invoked.", + field.getName(), cls.getSimpleName() ); } continue; } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/MethodSignatureCompiler.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/MethodSignatureCompiler.java index 1b5d8e95056b7..9800a67895676 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/MethodSignatureCompiler.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/MethodSignatureCompiler.java @@ -28,13 +28,8 @@ import org.neo4j.kernel.api.exceptions.ProcedureException; import org.neo4j.kernel.api.exceptions.Status; import org.neo4j.kernel.api.proc.ProcedureSignature.FieldSignature; -import org.neo4j.messages.Messages; import org.neo4j.procedure.Name; -import static org.neo4j.messages.Messages.proc_argument_missing_name; -import static org.neo4j.messages.Messages.proc_argument_name_empty; -import static org.neo4j.messages.Messages.proc_unmappable_argument_type; - /** * Given a java method, figures out a valid {@link org.neo4j.kernel.api.proc.ProcedureSignature} field signature. * Basically, it takes the java signature and spits out the same signature described as Neo4j types. @@ -61,15 +56,18 @@ public List signatureFor( Method method ) throws ProcedureExcept if ( !param.isAnnotationPresent( Name.class ) ) { throw new ProcedureException( Status.Procedure.FailedRegistration, - Messages.get( proc_argument_missing_name, i, method.getName(), - Name.class.getSimpleName()) ); + "Argument at position %d in method `%s` is missing an `@%s` annotation.\n" + + "Please add the annotation, recompile the class and try again.", + i, method.getName(), Name.class.getSimpleName() ); } String name = param.getAnnotation( Name.class ).value(); if( name.trim().length() == 0 ) { throw new ProcedureException( Status.Procedure.FailedRegistration, - Messages.get( proc_argument_name_empty, i, method.getName() ) ); + "Argument at position %d in method `%s` is annotated with a name,\n" + + "but the name is empty, please provide a non-empty name for the argument.", + i, method.getName() ); } try @@ -79,9 +77,10 @@ public List signatureFor( Method method ) throws ProcedureExcept catch ( ProcedureException e ) { throw new ProcedureException( e.status(), - Messages.get( proc_unmappable_argument_type, - name, i, method.getName(), param.getType().getSimpleName(), - e.getMessage() ) ); + "Argument `%s` at position %d in `%s` with\n" + + "type `%s` cannot be converted to a Neo4j type: %s", + name, i, method.getName(), param.getType().getSimpleName(), + e.getMessage() ); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/OutputMappers.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/OutputMappers.java index 74c9852d22182..e85e5fd9246a5 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/OutputMappers.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/OutputMappers.java @@ -33,13 +33,11 @@ import org.neo4j.kernel.api.exceptions.Status; import org.neo4j.kernel.api.proc.ProcedureSignature; import org.neo4j.kernel.api.proc.ProcedureSignature.FieldSignature; -import org.neo4j.messages.Messages; import static java.lang.reflect.Modifier.isPublic; import static java.lang.reflect.Modifier.isStatic; import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; -import static org.neo4j.messages.Messages.proc_invalid_return_type_description; /** * Takes user-defined record classes, and does two things: Describe the class as a {@link ProcedureSignature}, and provide a mechanism to convert @@ -136,8 +134,7 @@ public OutputMapper mapper( Method method ) throws ProcedureException if ( cls != Stream.class ) { - throw new ProcedureException( Status.Procedure.TypeError, - Messages.get( proc_invalid_return_type_description, cls.getSimpleName() )); + throw invalidReturnType( cls ); } ParameterizedType genType = (ParameterizedType) method.getGenericReturnType(); @@ -193,11 +190,24 @@ private void assertIsValidRecordClass( Class userClass ) throws ProcedureExce if( userClass.isPrimitive() || userClass.isArray() || userClass.getPackage() != null && userClass.getPackage().getName().startsWith( "java." ) ) { - throw new ProcedureException( Status.Procedure.TypeError, - Messages.get( proc_invalid_return_type_description, userClass.getSimpleName() )); + throw invalidReturnType( userClass ); } } + private ProcedureException invalidReturnType( Class userClass ) + { + return new ProcedureException( Status.Procedure.TypeError, + "Procedures must return a Stream of records, where a record is a concrete class\n" + + "that you define, with public non-final fields defining the fields in the record.\n" + + "If you''d like your procedure to return `%s`, you could define a record class like:\n" + + "public class Output '{'\n" + + " public %s out;\n" + + "'}'\n" + + "\n" + + "And then define your procedure as returning `Stream`.", + userClass.getSimpleName(), userClass.getSimpleName()); + } + private List instanceFields( Class userClass ) { return asList( userClass.getDeclaredFields() ).stream() diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/TypeMappers.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/TypeMappers.java index a3142622888f3..9940ddd19166e 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/TypeMappers.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/TypeMappers.java @@ -29,7 +29,6 @@ import org.neo4j.kernel.api.exceptions.ProcedureException; import org.neo4j.kernel.api.exceptions.Status; import org.neo4j.kernel.api.proc.Neo4jTypes.AnyType; -import org.neo4j.messages.Messages; import static org.neo4j.kernel.api.proc.Neo4jTypes.NTAny; import static org.neo4j.kernel.api.proc.Neo4jTypes.NTBoolean; @@ -39,7 +38,6 @@ import static org.neo4j.kernel.api.proc.Neo4jTypes.NTMap; import static org.neo4j.kernel.api.proc.Neo4jTypes.NTNumber; import static org.neo4j.kernel.api.proc.Neo4jTypes.NTString; -import static org.neo4j.messages.Messages.proc_unmappable_type; public class TypeMappers { @@ -146,7 +144,9 @@ private ProcedureException javaToNeoMappingError( Type cls ) types.sort( (a,b)->a.toString().compareTo( b.toString() ) ); return new ProcedureException( Status.Statement.InvalidType, - Messages.get( proc_unmappable_type, cls, types )); + "Don't know how to map `%s` to the Neo4j Type System.\n" + + "Please refer to to the documentation for full details.\n" + + "For your reference, known types are: %s", cls, types ); } public static class SimpleConverter implements NeoValueConverter diff --git a/community/kernel/src/main/java/org/neo4j/messages/Messages.java b/community/kernel/src/main/java/org/neo4j/messages/Messages.java deleted file mode 100644 index 4cd08f4f75d10..0000000000000 --- a/community/kernel/src/main/java/org/neo4j/messages/Messages.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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.messages; - -import java.text.MessageFormat; - -/** - * This is a beach head - if you are implementing code that prints human language - * messages in any way, through errors, warnings, explanations or any other - * mechanism - please help expand, refactor, move and use this this class to do - * so. - * - * The intention of this is to slowly introduce a proper i18n message API, - * backed by the standard i18n support in Java. - * - * The messages in this file are templates fed to the {@link MessageFormat} formatter. - * If you are including things like times, dates or other locale-sensitive things, - * please use the pattern utilities provided by {@link MessageFormat} to format them, - * since that will make it much easier to internationalize them in the future. - */ -public interface Messages -{ - // Note: Single-quotes, `'` and curly brackets have special meaning - // to MessageFormat and need to be escaped as "''" and "'{'", respectively. - - // Note: This file is going to become very large. As it does, please use - // best judgement to split it into appropriate categories and sub-files. - - Message proc_invalid_return_type_description = - msg("Procedures must return a Stream of records, where a record is a concrete class\n" + - "that you define, with public non-final fields defining the fields in the record.\n" + - "If you''d like your procedure to return `{0}`, you could define a record class like:\n" + - "public class Output '{'\n" + - " public {0} out;\n" + - "'}'\n" + - "\n" + - "And then define your procedure as returning `Stream`."); - - Message proc_static_field_annotated_as_context = - msg("The field `{0}` in the class named `{1}` is annotated as a @Context field,\n" + - "but it is static. @Context fields must be public, non-final and non-static,\n" + - "because they are reset each time a procedure is invoked."); - - Message proc_unmappable_type = - msg("Don''t know how to map `{0}` to the Neo4j Type System.\n" + - "Please refer to to the documentation for full details.\n" + - "For your reference, known types are: {1}"); - - Message proc_unmappable_argument_type = - msg("Argument `{0}` at position {1} in `{2}` with\n" + - "type `{3}` cannot be converted to a Neo4j type: {4}" ); - - Message proc_argument_missing_name = - msg("Argument at position {0} in method `{1}` is missing an `@{2}` annotation.\n" + - "Please add the annotation, recompile the class and try again." ); - - Message proc_argument_name_empty = - msg("Argument at position {0} in method `{1}` is annotated with a name,\n" + - "but the name is empty, please provide a non-empty name for the argument." ); - - interface Message - { - String defaultMessage(); - } - - // Implementation note: - // We use this silly-looking indirection of calling Messages#get(..) - // instead of just calling message.defaultMessage() wherever we need - // these messages. The reason is the intended direction of this interface, - // which is that we'd be able to plug i18n lookups in underneath, so if - // you in the future are running Neo4j with a German locale, you'd get - // german messages out on the other end. - - /** - * Get a message, optionally filling in positional arguments. - * @param msg the message to output - * @param args optional dynamic parts of the message - * @return the message with the dynamic parameters inserted - */ - static String get( Message msg, Object ... args ) - { - return MessageFormat.format( msg.defaultMessage(), args ); - } - - /** Create a new message */ - static Message msg(String defaultMessage) - { - return () -> defaultMessage; - } -}