From b5e672f92b3f3d99fe7d00c3be1b4a84392a6e51 Mon Sep 17 00:00:00 2001 From: Benjamin Bentmann Date: Sat, 6 Jun 2009 17:28:10 +0000 Subject: [PATCH] o Revised exception handling of model builder to collect as much as possible in ModelProblem instances that are stored in the ModelBuildingException when it eventually bails out. This should enable IDE integrators to provide more extensive error feedback. git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@782282 13f79535-47bb-0310-9956-ffa450edef68 --- .../maven/model/DefaultModelBuilder.java | 107 ++++++++++------ .../maven/model/InvalidModelException.java | 73 ----------- .../maven/model/InvalidProfileException.java | 59 --------- .../maven/model/ModelBuildingException.java | 49 ++++++-- .../org/apache/maven/model/ModelProblem.java | 118 ++++++++++++++++++ .../model/UnparseableModelException.java | 76 ----------- .../model/UnresolvableParentException.java | 52 -------- .../maven/model/path/PathTranslator.java | 2 +- 8 files changed, 225 insertions(+), 311 deletions(-) delete mode 100644 maven-model-builder/src/main/java/org/apache/maven/model/InvalidModelException.java delete mode 100644 maven-model-builder/src/main/java/org/apache/maven/model/InvalidProfileException.java create mode 100644 maven-model-builder/src/main/java/org/apache/maven/model/ModelProblem.java delete mode 100644 maven-model-builder/src/main/java/org/apache/maven/model/UnparseableModelException.java delete mode 100644 maven-model-builder/src/main/java/org/apache/maven/model/UnresolvableParentException.java diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/DefaultModelBuilder.java index a8db2187cb..9ba962affa 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/DefaultModelBuilder.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/DefaultModelBuilder.java @@ -110,17 +110,19 @@ public class DefaultModelBuilder { DefaultModelBuildingResult result = new DefaultModelBuildingResult(); + List problems = new ArrayList(); + ProfileActivationContext profileActivationContext = getProfileActivationContext( request ); - List activeExternalProfiles = getActiveExternalProfiles( request, profileActivationContext ); + List activeExternalProfiles = getActiveExternalProfiles( request, profileActivationContext, problems ); - Model model = readModel( modelSource, request ); + Model model = readModel( modelSource, request, problems ); model.setPomFile( pomFile ); List rawModels = new ArrayList(); List resultModels = new ArrayList(); - for ( Model current = model; current != null; current = readParent( current, request ) ) + for ( Model current = model; current != null; current = readParent( current, request, problems ) ) { Model resultModel = current; resultModels.add( resultModel ); @@ -130,7 +132,8 @@ public class DefaultModelBuilder modelNormalizer.mergeDuplicates( resultModel, request ); - List activeProjectProfiles = getActiveProjectProfiles( rawModel, profileActivationContext ); + List activeProjectProfiles = + getActiveProjectProfiles( rawModel, profileActivationContext, problems ); List activeProfiles = activeProjectProfiles; if ( current == model ) @@ -147,7 +150,7 @@ public class DefaultModelBuilder result.setActiveProfiles( rawModel, activeProfiles ); - configureResolver( request.getModelResolver(), resultModel ); + configureResolver( request.getModelResolver(), resultModel, problems ); } Model superModel = getSuperModel(); @@ -160,7 +163,7 @@ public class DefaultModelBuilder Model resultModel = resultModels.get( 0 ); - resultModel = interpolateModel( resultModel, request ); + resultModel = interpolateModel( resultModel, request, problems ); resultModels.set( 0, resultModel ); modelPathTranslator.alignToBaseDirectory( resultModel, resultModel.getProjectDirectory(), request ); @@ -177,7 +180,12 @@ public class DefaultModelBuilder pluginConfigurationExpander.expandPluginConfiguration( resultModel, request ); } - validateModel( resultModel, false, request ); + validateModel( resultModel, false, request, problems ); + + if ( !problems.isEmpty() ) + { + throw new ModelBuildingException( problems ); + } result.setEffectiveModel( resultModel ); @@ -193,7 +201,7 @@ public class DefaultModelBuilder return context; } - private Model readModel( ModelSource modelSource, ModelBuildingRequest request ) + private Model readModel( ModelSource modelSource, ModelBuildingRequest request, List problems ) throws ModelBuildingException { Model model; @@ -207,21 +215,23 @@ public class DefaultModelBuilder } catch ( ModelParseException e ) { - throw new UnparseableModelException( "Failed to parse POM " + modelSource.getLocation() + ": " - + e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e ); + problems.add( new ModelProblem( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage(), + modelSource.getLocation(), e ) ); + throw new ModelBuildingException( problems ); } catch ( IOException e ) { - throw new UnparseableModelException( "Failed to read POM " + modelSource.getLocation(), -1, -1, e ); + problems.add( new ModelProblem( "Non-readable POM " + modelSource.getLocation() + ": " + e.getMessage(), + modelSource.getLocation(), e ) ); + throw new ModelBuildingException( problems ); } - validateModel( model, true, request ); + validateModel( model, true, request, problems ); return model; } - private void validateModel( Model model, boolean raw, ModelBuildingRequest request ) - throws ModelBuildingException + private void validateModel( Model model, boolean raw, ModelBuildingRequest request, List problems ) { ModelValidationResult result; @@ -236,12 +246,17 @@ public class DefaultModelBuilder if ( result.getMessageCount() > 0 ) { - throw new InvalidModelException( "Failed to validate POM " + toSourceHint( model ), result ); + String source = toSourceHint( model ); + + for ( int i = 0; i < result.getMessageCount(); i++ ) + { + problems.add( new ModelProblem( "Invalid POM " + source + ": " + result.getMessage( i ), source ) ); + } } } - private List getActiveExternalProfiles( ModelBuildingRequest request, ProfileActivationContext context ) - throws ModelBuildingException + private List getActiveExternalProfiles( ModelBuildingRequest request, ProfileActivationContext context, + List problems ) { try { @@ -249,12 +264,16 @@ public class DefaultModelBuilder } catch ( ProfileActivationException e ) { - throw new InvalidProfileException( "Failed to determine activation status of external profile " - + e.getProfile(), e.getProfile(), e ); + problems.add( new ModelProblem( "Invalid activation condition for external profile " + + e.getProfile().getId() + ": " + e.getMessage(), "(external profiles)", e ) ); + + // FIXME: Update profile selector to integrate better with the problem reporting + return new ArrayList(); } } - private List getActiveProjectProfiles( Model model, ProfileActivationContext context ) + private List getActiveProjectProfiles( Model model, ProfileActivationContext context, + List problems ) throws ModelBuildingException { try @@ -263,13 +282,16 @@ public class DefaultModelBuilder } catch ( ProfileActivationException e ) { - throw new InvalidProfileException( "Failed to determine activation status of project profile " - + e.getProfile() + " for POM " + toSourceHint( model ), e.getProfile(), e ); + problems.add( new ModelProblem( "Invalid activation condition for project profile " + + e.getProfile().getId() + " in POM " + toSourceHint( model ) + ": " + e.getMessage(), + toSourceHint( model ), e ) ); + + // FIXME: Update profile selector to integrate better with the problem reporting + return new ArrayList(); } } - private void configureResolver( ModelResolver modelResolver, Model model ) - throws ModelBuildingException + private void configureResolver( ModelResolver modelResolver, Model model, List problems ) { if ( modelResolver == null ) { @@ -284,8 +306,8 @@ public class DefaultModelBuilder } catch ( InvalidRepositoryException e ) { - throw new InvalidModelException( "Failed to validate repository " + repository.getId() + " for POM " - + toSourceHint( model ), e ); + problems.add( new ModelProblem( "Invalid repository " + repository.getId() + " in POM " + + toSourceHint( model ) + ": " + e.getMessage(), toSourceHint( model ), e ) ); } } } @@ -300,8 +322,7 @@ public class DefaultModelBuilder } } - private Model interpolateModel( Model model, ModelBuildingRequest request ) - throws ModelBuildingException + private Model interpolateModel( Model model, ModelBuildingRequest request, List problems ) { try { @@ -311,11 +332,14 @@ public class DefaultModelBuilder } catch ( ModelInterpolationException e ) { - throw new ModelBuildingException( "Failed to interpolate model " + toSourceHint( model ), e ); + problems.add( new ModelProblem( "Invalid expression in POM " + toSourceHint( model ) + ": " + + e.getMessage(), toSourceHint( model ), e ) ); + + return model; } } - private Model readParent( Model childModel, ModelBuildingRequest request ) + private Model readParent( Model childModel, ModelBuildingRequest request, List problems ) throws ModelBuildingException { Model parentModel; @@ -324,11 +348,11 @@ public class DefaultModelBuilder if ( parent != null ) { - parentModel = readParentLocally( childModel, request ); + parentModel = readParentLocally( childModel, request, problems ); if ( parentModel == null ) { - parentModel = readParentExternally( childModel, request ); + parentModel = readParentExternally( childModel, request, problems ); } } else @@ -339,7 +363,7 @@ public class DefaultModelBuilder return parentModel; } - private Model readParentLocally( Model childModel, ModelBuildingRequest request ) + private Model readParentLocally( Model childModel, ModelBuildingRequest request, List problems ) throws ModelBuildingException { File projectDirectory = childModel.getProjectDirectory(); @@ -360,7 +384,7 @@ public class DefaultModelBuilder return null; } - Model candidateModel = readModel( new FileModelSource( pomFile ), request ); + Model candidateModel = readModel( new FileModelSource( pomFile ), request, problems ); candidateModel.setPomFile( pomFile ); String groupId = candidateModel.getGroupId(); @@ -391,7 +415,7 @@ public class DefaultModelBuilder return candidateModel; } - private Model readParentExternally( Model childModel, ModelBuildingRequest request ) + private Model readParentExternally( Model childModel, ModelBuildingRequest request, List problems ) throws ModelBuildingException { Parent parent = childModel.getParent(); @@ -400,9 +424,9 @@ public class DefaultModelBuilder if ( modelResolver == null ) { - Exception e = new IllegalArgumentException( "No model resolver provided" ); - throw new UnresolvableParentException( "Failed to resolve parent POM " + toId( parent ) + " for POM " - + toSourceHint( childModel ), e ); + problems.add( new ModelProblem( "Non-resolvable parent POM " + toId( parent ) + " for POM " + + toSourceHint( childModel ) + ": " + "No model resolver provided", toSourceHint( childModel ) ) ); + throw new ModelBuildingException( problems ); } ModelSource modelSource; @@ -412,11 +436,12 @@ public class DefaultModelBuilder } catch ( UnresolvableModelException e ) { - throw new UnresolvableParentException( "Failed to resolve parent POM " + toId( parent ) + " for POM " - + toSourceHint( childModel ), e ); + problems.add( new ModelProblem( "Non-resolvable parent POM " + toId( parent ) + " for POM " + + toSourceHint( childModel ) + ": " + e.getMessage(), toSourceHint( childModel ), e ) ); + throw new ModelBuildingException( problems ); } - return readModel( modelSource, request ); + return readModel( modelSource, request, problems ); } private Model getSuperModel() diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/InvalidModelException.java b/maven-model-builder/src/main/java/org/apache/maven/model/InvalidModelException.java deleted file mode 100644 index 93462c653d..0000000000 --- a/maven-model-builder/src/main/java/org/apache/maven/model/InvalidModelException.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.apache.maven.model; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -import org.apache.maven.model.validation.ModelValidationResult; - -/** - * Signals an error due to invalid or missing model values. - * - * @author Benjamin Bentmann - */ -public class InvalidModelException - extends ModelBuildingException -{ - - /** - * The validation result, can be {@code null}. - */ - private ModelValidationResult validationResult; - - /** - * Creates a new exception with specified detail message and validation result. - * - * @param message The detail message, may be {@code null}. - * @param validationResult The validation result, may be {@code null}. - */ - public InvalidModelException( String message, ModelValidationResult validationResult ) - { - super( message ); - this.validationResult = validationResult; - } - - /** - * Creates a new exception with specified detail message and cause. - * - * @param message The detail message, may be {@code null}. - * @param cause The cause, may be {@code null}. - */ - public InvalidModelException( String message, Throwable cause ) - { - super( message, cause ); - validationResult = new ModelValidationResult(); - validationResult.addMessage( ( cause != null ) ? cause.getMessage() : message ); - } - - /** - * Gets the validation result. - * - * @return The validation result or {@code null} if unknown. - */ - public ModelValidationResult getValidationResult() - { - return validationResult; - } - -} diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/InvalidProfileException.java b/maven-model-builder/src/main/java/org/apache/maven/model/InvalidProfileException.java deleted file mode 100644 index c43c601f4a..0000000000 --- a/maven-model-builder/src/main/java/org/apache/maven/model/InvalidProfileException.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.apache.maven.model; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -/** - * Signals an error during profile activation. - * - * @author Benjamin Bentmann - */ -public class InvalidProfileException - extends ModelBuildingException -{ - - /** - * The profile which raised this error, can be {@code null}. - */ - private Profile profile; - - /** - * Creates a new exception with specified detail message and cause for the given profile. - * - * @param message The detail message, may be {@code null}. - * @param profile The profile that caused the error, may be {@code null}. - * @param cause The cause, may be {@code null}. - */ - public InvalidProfileException( String message, Profile profile, Throwable cause ) - { - super( message ); - this.profile = profile; - } - - /** - * Gets the profile that caused this error (if any). - * - * @return The profile that caused this error or {@code null} if not applicable. - */ - public Profile getProfile() - { - return profile; - } - -} diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/ModelBuildingException.java b/maven-model-builder/src/main/java/org/apache/maven/model/ModelBuildingException.java index 82d0fb4695..83f712c670 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/ModelBuildingException.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/ModelBuildingException.java @@ -19,6 +19,11 @@ package org.apache.maven.model; * under the License. */ +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + /** * Signals an error during model building. * @@ -28,25 +33,51 @@ public class ModelBuildingException extends Exception { + private List problems; + /** - * Creates a new exception with specified detail message. + * Creates a new exception with the specified problems. * - * @param message The detail message, may be {@code null}. + * @param problems The problems that causes this exception, may be {@code null}. */ - public ModelBuildingException( String message ) + public ModelBuildingException( List problems ) { - super( message ); + super( toMessage( problems ) ); + + this.problems = new ArrayList(); + if ( problems != null ) + { + this.problems.addAll( problems ); + } } /** - * Creates a new exception with specified detail message and cause. + * Gets the problems that caused this exception. * - * @param message The detail message, may be {@code null}. - * @param cause The cause, may be {@code null}. + * @return The problems that caused this exception, never {@code null}. */ - public ModelBuildingException( String message, Throwable cause ) + public List getProblems() { - super( message, cause ); + return this.problems; + } + + private static String toMessage( List problems ) + { + StringWriter buffer = new StringWriter( 1024 ); + + PrintWriter writer = new PrintWriter( buffer ); + + writer.print( problems.size() ); + writer.print( ( problems.size() == 1 ) ? " problem was " : " problems were " ); + writer.println( "encountered during construction of the effective model:" ); + + for ( ModelProblem problem : problems ) + { + writer.print( "o " ); + writer.println( problem.getMessage() ); + } + + return buffer.toString(); } } diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/ModelProblem.java b/maven-model-builder/src/main/java/org/apache/maven/model/ModelProblem.java new file mode 100644 index 0000000000..d2b3629d46 --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/ModelProblem.java @@ -0,0 +1,118 @@ +package org.apache.maven.model; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * Describes a problem that was encountered during model building. A problem can either be an exception that was thrown + * or a simple string message. In addition, a problem carries a hint about its source, e.g. the POM file that could not + * be processed. + * + * @author Benjamin Bentmann + */ +public class ModelProblem +{ + + private String source; + + private String message; + + private Exception exception; + + /** + * Creates a new problem with the specified message. + * + * @param message The message describing the problem, may be {@code null}. + * @param source A hint about the source of the problem, may be {@code null}. + */ + public ModelProblem( String message, String source ) + { + this.message = message; + this.source = ( source != null ) ? source : ""; + } + + /** + * Creates a new problem with the specified message and exception. + * + * @param message The message describing the problem, may be {@code null}. + * @param source A hint about the source of the problem, may be {@code null}. + * @param exception The exception that caused this problem, may be {@code null}. + */ + public ModelProblem( String message, String source, Exception exception ) + { + this.message = message; + this.source = ( source != null ) ? source : ""; + this.exception = exception; + } + + /** + * Gets the hint about the source of the problem. While the syntax of this hint is unspecified and depends on the + * creator of the problem, the general expectation is that the hint provides sufficient information to the user to + * track the problem back to its origin. + * + * @return The hint about the source of the problem, never {@code null}. + */ + public String getSource() + { + return source; + } + + /** + * Gets the exception that caused this problem (if any). + * + * @return The exception that caused this problem or {@code null} if not applicable. + */ + public Exception getException() + { + return exception; + } + + /** + * Gets the message that describes this problem. + * + * @return The message describing this problem, never {@code null}. + */ + public String getMessage() + { + String msg; + + if ( message != null && message.length() > 0 ) + { + msg = message; + } + else + { + msg = exception.getMessage(); + + if ( msg == null ) + { + msg = ""; + } + } + + return msg; + } + + @Override + public String toString() + { + return getSource() + ": " + getMessage(); + } + +} diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/UnparseableModelException.java b/maven-model-builder/src/main/java/org/apache/maven/model/UnparseableModelException.java deleted file mode 100644 index 4c247428e2..0000000000 --- a/maven-model-builder/src/main/java/org/apache/maven/model/UnparseableModelException.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.apache.maven.model; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -/** - * Signals a failure to read/parse a POM file. - * - * @author Benjamin Bentmann - */ -public class UnparseableModelException - extends ModelBuildingException -{ - - /** - * The one-based index of the line containing the error. - */ - private int lineNumber; - - /** - * The one-based index of the column containing the error. - */ - private int columnNumber; - - /** - * Creates a new parser exception with the specified details. - * - * @param message The error message, may be {@code null}. - * @param lineNumber The one-based index of the line containing the error or {@code -1} if unknown. - * @param columnNumber The one-based index of the column containing the error or {@code -1} if unknown. - * @param cause The nested cause of this error, may be {@code null}. - */ - public UnparseableModelException( String message, int lineNumber, int columnNumber, Throwable cause ) - { - super( message, cause ); - this.lineNumber = lineNumber; - this.columnNumber = columnNumber; - } - - /** - * Gets the one-based index of the line containing the error. - * - * @return The one-based index of the line containing the error or a non-positive value if unknown. - */ - public int getLineNumber() - { - return lineNumber; - } - - /** - * Gets the one-based index of the column containing the error. - * - * @return The one-based index of the column containing the error or non-positive value if unknown. - */ - public int getColumnNumber() - { - return columnNumber; - } - -} diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/UnresolvableParentException.java b/maven-model-builder/src/main/java/org/apache/maven/model/UnresolvableParentException.java deleted file mode 100644 index 86e554953b..0000000000 --- a/maven-model-builder/src/main/java/org/apache/maven/model/UnresolvableParentException.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.apache.maven.model; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -/** - * Signals an error when resolving a child's parent model. - * - * @author Benjamin Bentmann - */ -public class UnresolvableParentException - extends ModelBuildingException -{ - - /** - * Creates a new exception with specified detail message and cause. - * - * @param message The detail message, may be {@code null}. - * @param cause The cause, may be {@code null}. - */ - public UnresolvableParentException( String message, Throwable cause ) - { - super( message, cause ); - } - - /** - * Creates a new exception with specified detail message. - * - * @param message The detail message, may be {@code null}. - */ - public UnresolvableParentException( String message ) - { - super( message ); - } - -} diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java index 3d136a32d4..349711d50c 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java @@ -31,7 +31,7 @@ public interface PathTranslator /** * Resolves the specified path against the given base directory. The resolved path will be absolute and uses the - * platform-specified file separator. + * platform-specific file separator. * * @param path The path to resolve, may be {@code null}. * @param basedir The base directory to resolve relative paths against, may be {@code null}.