Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@
* parse for a particular name
*/
public class NamedObjectNotFoundException extends XContentParseException {
private final Iterable<String> candidates;

public NamedObjectNotFoundException(String message) {
this(null, message);
public NamedObjectNotFoundException(XContentLocation location, String message, Iterable<String> candidates) {
super(location, message);
this.candidates = candidates;
}

public NamedObjectNotFoundException(XContentLocation location, String message) {
super(location, message);
/**
* The possible matches.
*/
public Iterable<String> getCandidates() {
return candidates;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,19 +123,18 @@ public <T, C> T parseNamedObject(Class<T> categoryClass, String name, XContentPa
if (parsers == null) {
if (registry.isEmpty()) {
// The "empty" registry will never work so we throw a better exception as a hint.
throw new NamedObjectNotFoundException("named objects are not supported for this parser");
throw new XContentParseException("named objects are not supported for this parser");
}
throw new NamedObjectNotFoundException("unknown named object category [" + categoryClass.getName() + "]");
throw new XContentParseException("unknown named object category [" + categoryClass.getName() + "]");
}
Entry entry = parsers.get(name);
if (entry == null) {
throw new NamedObjectNotFoundException(parser.getTokenLocation(), "unable to parse " + categoryClass.getSimpleName() +
" with name [" + name + "]: parser not found");
throw new NamedObjectNotFoundException(parser.getTokenLocation(), "unknown field [" + name + "]", parsers.keySet());
}
if (false == entry.name.match(name, parser.getDeprecationHandler())) {
/* Note that this shouldn't happen because we already looked up the entry using the names but we need to call `match` anyway
* because it is responsible for logging deprecation warnings. */
throw new NamedObjectNotFoundException(parser.getTokenLocation(),
throw new XContentParseException(parser.getTokenLocation(),
"unable to parse " + categoryClass.getSimpleName() + " with name [" + name + "]: parser didn't match");
}
return categoryClass.cast(entry.parser.parse(parser, context));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
Expand Down Expand Up @@ -140,8 +142,10 @@ private static <Value, Category, Context> UnknownFieldParser<Value, Context> unk
try {
o = parser.namedObject(categoryClass, field, context);
} catch (NamedObjectNotFoundException e) {
// TODO It'd be lovely if we could the options here but we don't have the right stuff plumbed through. We'll get to it!
throw new XContentParseException(location, "[" + objectParser.name + "] " + e.getBareMessage(), e);
Set<String> candidates = new HashSet<>(objectParser.fieldParserMap.keySet());
e.getCandidates().forEach(candidates::add);
String message = ErrorOnUnknown.IMPLEMENTATION.errorMessage(objectParser.name, field, candidates);
throw new XContentParseException(location, message, e);
}
consumer.accept(value, o);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,6 @@ public XContentLocation getLocation() {

@Override
public String getMessage() {
return location.map(l -> "[" + l.toString() + "] ").orElse("") + getBareMessage();
}

/**
* Get the exception message without location information.
*/
public String getBareMessage() {
return super.getMessage();
return location.map(l -> "[" + l.toString() + "] ").orElse("") + super.getMessage();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
Expand Down Expand Up @@ -804,7 +805,9 @@ public void testTopLevelNamedXContent() throws IOException {
{
XContentParser parser = createParser(JsonXContent.jsonXContent, "{\"not_supported_field\" : \"foo\"}");
XContentParseException ex = expectThrows(XContentParseException.class, () -> TopLevelNamedXConent.PARSER.parse(parser, null));
assertEquals("[1:2] [test] unable to parse Object with name [not_supported_field]: parser not found", ex.getMessage());
assertEquals("[1:2] [test] unknown field [not_supported_field]", ex.getMessage());
NamedObjectNotFoundException cause = (NamedObjectNotFoundException) ex.getCause();
assertThat(cause.getCandidates(), containsInAnyOrder("str", "int", "float", "bool"));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,18 @@
search:
rest_total_hits_as_int: true
body: { "size" : 0, "aggs" : { "ip_terms" : { "significant_terms" : { "field" : "ip", "exclude" : "127.*" } } } }

---
'Misspelled fields get "did you mean"':
- skip:
version: " - 7.99.99"
reason: Implemented in 8.0 (to be backported to 7.7)
- do:
catch: /\[significant_terms\] unknown field \[jlp\] did you mean \[jlh\]\?/
search:
body:
aggs:
foo:
significant_terms:
field: foo
jlp: {}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;

import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.Constants;
import org.elasticsearch.cluster.metadata.IndexMetaData;
Expand Down Expand Up @@ -78,6 +79,7 @@
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo;
Expand Down Expand Up @@ -1169,16 +1171,17 @@ public void testNamedObject() throws IOException {
{
NamedObjectNotFoundException e = expectThrows(NamedObjectNotFoundException.class,
() -> p.namedObject(Object.class, "unknown", null));
assertThat(e.getMessage(), endsWith("unable to parse Object with name [unknown]: parser not found"));
assertThat(e.getMessage(), endsWith("unknown field [unknown]"));
assertThat(e.getCandidates(), containsInAnyOrder("test1", "test2", "deprecated", "str"));
}
{
Exception e = expectThrows(NamedObjectNotFoundException.class, () -> p.namedObject(String.class, "doesn't matter", null));
Exception e = expectThrows(XContentParseException.class, () -> p.namedObject(String.class, "doesn't matter", null));
assertEquals("unknown named object category [java.lang.String]", e.getMessage());
}
}
try (XContentParser emptyRegistryParser = xcontentType().xContent()
.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, new byte[] {})) {
Exception e = expectThrows(NamedObjectNotFoundException.class,
Exception e = expectThrows(XContentParseException.class,
() -> emptyRegistryParser.namedObject(String.class, "doesn't matter", null));
assertEquals("named objects are not supported for this parser", e.getMessage());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public void testParseTypedKeysObject() throws IOException {
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
NamedObjectNotFoundException e = expectThrows(NamedObjectNotFoundException.class,
() -> parseTypedKeysObject(parser, delimiter, Boolean.class, a -> {}));
assertThat(e.getMessage(), endsWith("unable to parse Boolean with name [type]: parser not found"));
assertThat(e.getMessage(), endsWith("unknown field [type]"));
}

final long longValue = randomLong();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterModule;
import org.elasticsearch.cluster.metadata.IndexGraveyard;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.metadata.RepositoriesMetaData;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
Expand Down Expand Up @@ -277,7 +280,7 @@ private void runLoadStateTest(boolean hasMissingCustoms, boolean preserveUnknown
List<Path> dirList = Arrays.asList(dirs);
Collections.shuffle(dirList, random());
MetaData loadedMetaData = format.loadLatestState(logger, hasMissingCustoms ?
NamedXContentRegistry.EMPTY : xContentRegistry(), dirList.toArray(new Path[0]));
xContentRegistryWithMissingCustoms() : xContentRegistry(), dirList.toArray(new Path[0]));
MetaData latestMetaData = meta.get(numStates-1);
assertThat(loadedMetaData.clusterUUID(), not(equalTo("_na_")));
assertThat(loadedMetaData.clusterUUID(), equalTo(latestMetaData.clusterUUID()));
Expand Down Expand Up @@ -706,4 +709,20 @@ public long addDummyFiles(String prefix, Path... paths) throws IOException {
}
return realId + 1;
}

/**
* The {@link NamedXContentRegistry} to use for most {@link XContentParser} in this test.
*/
protected final NamedXContentRegistry xContentRegistry() {
return new NamedXContentRegistry(ClusterModule.getNamedXWriteables());
}

/**
* The {@link NamedXContentRegistry} to use for {@link XContentParser}s that should be
* missing all of the normal cluster state parsers.
*/
protected NamedXContentRegistry xContentRegistryWithMissingCustoms() {
return new NamedXContentRegistry(Arrays.asList(
new NamedXContentRegistry.Entry(MetaData.Custom.class, new ParseField("garbage"), RepositoriesMetaData::fromXContent)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ public void testUnknownFieldsExpection() throws IOException {
"}\n";
try (XContentParser parser = createParser(rescoreElement)) {
Exception e = expectThrows(NamedObjectNotFoundException.class, () -> RescorerBuilder.parseFromXContent(parser));
assertEquals("[3:27] unable to parse RescorerBuilder with name [bad_rescorer_name]: parser not found", e.getMessage());
assertEquals("[3:27] unknown field [bad_rescorer_name]", e.getMessage());
}
rescoreElement = "{\n" +
" \"bad_fieldName\" : 20\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public void testUnknownSuggestionTypeThrows() throws IOException {
ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation);
ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.nextToken(), parser::getTokenLocation);
NamedObjectNotFoundException e = expectThrows(NamedObjectNotFoundException.class, () -> Suggestion.fromXContent(parser));
assertEquals("[1:31] unable to parse Suggestion with name [unknownType]: parser not found", e.getMessage());
assertEquals("[1:31] unknown field [unknownType]", e.getMessage());
}
}

Expand Down