Added value parse exception

This allows distinct cases where error messages resulting from value
parse exception should not include additional information.
This commit is contained in:
nsingh
2017-01-23 15:08:41 -08:00
parent 26544461b8
commit ef00527a9e
11 changed files with 75 additions and 29 deletions

View File

@@ -25,7 +25,7 @@ public class AlwaysFailingParser implements ValueParser {
}
@Override
public Object parse(String str) {
public Object parse(String str) throws Exception {
throw new IllegalArgumentException("'"+str+"' is not valid for type '"+typeName+"'");
}

View File

@@ -44,11 +44,11 @@ public class EnumValueParser implements ValueParser {
this.values = values;
}
public Object parse(String str) {
public Object parse(String str) throws Exception {
// IMPORTANT: check the text FIRST before fetching values
// from the hints provider, as the hints provider may be expensive when resolving values
if (!StringUtil.hasText(str)) {
throw new IllegalArgumentException(createBlankTextErrorMessage());
throw toError(createBlankTextErrorMessage());
}
Collection<String> values = this.values.get();
@@ -57,9 +57,13 @@ public class EnumValueParser implements ValueParser {
if (values==null || values.contains(str)) {
return str;
} else {
throw new IllegalArgumentException(createErrorMessage(str, values));
throw toError(createErrorMessage(str, values));
}
}
protected Exception toError(String message) throws Exception{
return ExceptionUtil.asValueParseException(message);
}
protected String createBlankTextErrorMessage() {
return "'"+typeName+"'" + " cannot be blank.";

View File

@@ -61,22 +61,26 @@ public class ExceptionUtil {
// The message of nested exception is usually more interesting than the
// one on top.
Throwable cause = getDeepestCause(e);
String msg = cause.getClass().getSimpleName() + ": " + cause.getMessage();
return msg;
// If value parse exception, do not append any additional information
if (cause instanceof ValueParseException) {
String msg = cause.getMessage();
if (StringUtil.hasText(msg)) {
return msg;
} else {
return "An error occurred: " + getSimpleError(cause);
}
} else if (cause != null) {
String msg = getSimpleError(cause) + ": " + cause.getMessage();
return msg;
} else {
return "An error occurred: " + getSimpleError(e);
}
}
private static String getSimpleError(Throwable e) {
return e.getClass().getSimpleName();
}
/**
*
* @param e
* @return only the message in the error without any appended information
*/
public static String getMessageOnly(Throwable e) {
// The message of nested exception is usually more interesting than the
// one on top.
Throwable cause = getDeepestCause(e);
String msg = cause.getMessage();
return msg;
}
public static IllegalStateException notImplemented(String string) {
return new IllegalStateException("Not implemented: " + string);
@@ -131,4 +135,8 @@ public class ExceptionUtil {
return exception(error);
}
}
public static Exception asValueParseException(String message) {
return new ValueParseException(message);
}
}

View File

@@ -36,7 +36,7 @@ public class RegexpParser implements ValueParser {
}
@Override
public Object parse(String str) {
public Object parse(String str) throws Exception {
Matcher matcher = pat.matcher(str);
if (matcher.matches()) {
return matcher;

View File

@@ -0,0 +1,30 @@
/*******************************************************************************
* Copyright (c) 2017 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.util;
/**
* Exception if there is a failure when parsing a value. It does not wrap
* other exceptions such that when thrown, the parse exception is the "deepest"
* error.
*
*/
public class ValueParseException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
public ValueParseException(String message) {
super(message);
}
}

View File

@@ -22,5 +22,5 @@ public interface ValueParser {
* May either return null, or throw an {@link IllegalArgumentException} to indicate
* that the String is not the format this parser expects.
*/
Object parse(String str);
Object parse(String str) throws Exception;
}

View File

@@ -35,7 +35,7 @@ public class ValueParsers {
Assert.isLegal(lowerBound==null || upperBound==null || lowerBound <= upperBound);
return new ValueParser() {
@Override
public Object parse(String str) {
public Object parse(String str) throws Exception {
int value = Integer.parseInt(str);
if (lowerBound!=null && value<lowerBound) {
if (lowerBound==0) {

View File

@@ -155,7 +155,7 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
values = typeUtil.getHintValues(type, getSchemaContext());
} catch (Exception e) {
DocumentEdits edits = new DocumentEdits(doc.getDocument());
return ImmutableList.of(completionFactory().errorMessage(ExceptionUtil.getMessageOnly(e), query, type, edits, typeUtil));
return ImmutableList.of(completionFactory().errorMessage(ExceptionUtil.getMessage(e), query, type, edits, typeUtil));
}
if (values!=null) {
ArrayList<ICompletionProposal> completions = new ArrayList<>();

View File

@@ -47,7 +47,7 @@ public abstract class AbstractCFHintsProvider implements Callable<Collection<YVa
hints.addAll(resolvedHints);
}
} catch (Throwable e) {
// Convert any non "no-target" errors to something useful. The
// Convert any non "no-target" errors to something readable. The
// "no-target" errors
// are generated by the target provider so they should be propagated
// as is without further
@@ -57,12 +57,12 @@ public abstract class AbstractCFHintsProvider implements Callable<Collection<YVa
logger.log(Level.SEVERE, e.getMessage(), e);
if (ExceptionUtil.getThrowable(e, IOException.class) != null) {
throw ExceptionUtil.exception(
"Connection failure to Cloud Foundry. Please check the log for more details.", e);
throw ExceptionUtil.asValueParseException(
"Connection failure to Cloud Foundry. Please check the log for more details.");
} else {
throw ExceptionUtil.exception(
"Failed to fetch values from Cloud Foundry. Please check the log for more details.", e);
throw ExceptionUtil.asValueParseException(
"Failed to fetch values from Cloud Foundry. Please check the log for more details.");
}
}
else {

View File

@@ -24,5 +24,9 @@ public class CFServicesValueParser extends EnumValueParser {
protected String createErrorMessage(String parseString, Collection<String> values) {
return "There is no service instance called '" + parseString + "'. Available service instances are: " + values;
}
protected String createBlankTextErrorMessage() {
return "At least one service instance name must be specified";
}
}

View File

@@ -40,7 +40,7 @@ public class ManifestYmlValueParsers {
private final Set<String> UNITS = Sets.union(GIGABYTE, MEGABYTE);
@Override
public Object parse(String str) {
public Object parse(String str) throws Exception {
str = str.trim();
String unit = getUnit(str.toUpperCase());
if (unit==null) {
@@ -75,7 +75,7 @@ public class ManifestYmlValueParsers {
Assert.isLegal(lowerBound==null || upperBound==null || lowerBound <= upperBound);
return new ValueParser() {
@Override
public Object parse(String str) {
public Object parse(String str) throws Exception {
int value = Integer.parseInt(str);
if (lowerBound!=null && value<lowerBound) {
if (lowerBound==0) {