A content processing library for Elasticsearch that provides abstractions for parsing and generating various content formats including JSON, YAML, CBOR, and Smile.
—
The X-Content library provides comprehensive configuration system for parsers including named object registries, deprecation handling, API versioning, and field filtering support.
Central configuration interface for customizing parser behavior.
/**
* Configuration interface for XContentParser instances
*/
public interface XContentParserConfiguration {
/**
* Empty configuration with default settings - creates parsers that don't support named objects,
* throw exceptions on deprecated fields, return current REST API version, and do no filtering
*/
XContentParserConfiguration EMPTY = XContentProvider.provider().empty();
/**
* Control whether to include source in parsing error messages
* @param includeSourceOnError whether to include source on errors (defaults to true)
* @return new configuration with the specified setting
*/
XContentParserConfiguration withIncludeSourceOnError(boolean includeSourceOnError);
/**
* Check if source should be included in parsing error messages
* @return true if source should be included on errors
*/
boolean includeSourceOnError();
/**
* Create new configuration with specified registry
* @param registry named XContent registry
* @return new configuration with the registry
*/
XContentParserConfiguration withRegistry(NamedXContentRegistry registry);
/**
* Get the named XContent registry
* @return NamedXContentRegistry instance
*/
NamedXContentRegistry registry();
/**
* Create new configuration with specified deprecation handler
* @param handler deprecation handler
* @return new configuration with the handler
*/
XContentParserConfiguration withDeprecationHandler(DeprecationHandler handler);
/**
* Get the deprecation handler
* @return DeprecationHandler instance
*/
DeprecationHandler deprecationHandler();
/**
* Create new configuration with specified REST API version
* @param version REST API version
* @return new configuration with the version
*/
XContentParserConfiguration withRestApiVersion(RestApiVersion version);
/**
* Get the REST API version
* @return RestApiVersion instance
*/
RestApiVersion restApiVersion();
/**
* Create new configuration with filtering settings (legacy method)
* @param includeStrings field patterns to include
* @param excludeStrings field patterns to exclude
* @param filtersMatchFieldNamesWithDots whether filters should match field names containing dots
* @return new configuration with filtering
*/
XContentParserConfiguration withFiltering(Set<String> includeStrings, Set<String> excludeStrings,
boolean filtersMatchFieldNamesWithDots);
/**
* Create new configuration with advanced filtering settings
* @param prefixPath path to be prepended to each sub-path before applying include/exclude rules (null for root)
* @param includeStrings field patterns to include (only these paths will be included if specified)
* @param excludeStrings field patterns to exclude (these paths will be excluded if specified)
* @param filtersMatchFieldNamesWithDots whether filters should match field names containing dots as part of field name
* @return new configuration with filtering
*/
XContentParserConfiguration withFiltering(String prefixPath, Set<String> includeStrings,
Set<String> excludeStrings, boolean filtersMatchFieldNamesWithDots);
}Usage Examples:
import org.elasticsearch.xcontent.*;
// Use default configuration
XContentParserConfiguration defaultConfig = XContentParserConfiguration.EMPTY;
// Create custom registry
NamedXContentRegistry.Entry queryEntry = new NamedXContentRegistry.Entry(
Query.class, new ParseField("match"), MatchQuery::fromXContent);
NamedXContentRegistry customRegistry = new NamedXContentRegistry(List.of(queryEntry));
// Configure parser with custom settings
XContentParserConfiguration config = XContentParserConfiguration.EMPTY
.withRegistry(customRegistry)
.withDeprecationHandler(DeprecationHandler.IGNORE_DEPRECATIONS)
.withRestApiVersion(RestApiVersion.current());
// Create parser with configuration
XContentParser parser = XContentType.JSON.xContent()
.createParser(config, jsonContent);
// Configuration with filtering (legacy method)
XContentParserConfiguration filterConfig = XContentParserConfiguration.EMPTY
.withFiltering(Set.of("name", "age"), Set.of("internal.*"), false);
// Configuration with advanced filtering
XContentParserConfiguration advancedFilterConfig = XContentParserConfiguration.EMPTY
.withFiltering("user", Set.of("name", "age"), Set.of("internal.*"), true);
// Configuration with source error handling
XContentParserConfiguration errorConfig = XContentParserConfiguration.EMPTY
.withIncludeSourceOnError(false);Registry system for named objects like queries, aggregations, and other pluggable components.
/**
* Registry for named XContent parsers enabling pluggable object parsing
*/
public class NamedXContentRegistry {
/**
* Registry entry associating category, name, and parser
*/
public static class Entry {
/**
* Create a registry entry
* @param categoryClass class representing the category (e.g., Query.class)
* @param name parse field for the object name
* @param parser context parser for the object
*/
public <T> Entry(Class<T> categoryClass, ParseField name, ContextParser<Object, T> parser);
/**
* Get the category class
* @return category class
*/
public Class<?> getCategoryClass();
/**
* Get the name parse field
* @return ParseField with names
*/
public ParseField getName();
/**
* Get the parser
* @return ContextParser instance
*/
public ContextParser<Object, ?> getParser();
}
/**
* Empty registry with no entries
*/
public static final NamedXContentRegistry EMPTY = new NamedXContentRegistry(Collections.emptyList());
/**
* Create registry with list of entries
* @param entries list of registry entries
*/
public NamedXContentRegistry(List<Entry> entries);
/**
* Parse a named object from content
* @param categoryClass category class for the object
* @param name object name to parse
* @param parser content parser
* @param context parsing context
* @return parsed object of the specified type
*/
public <T, C> T parseNamedObject(Class<T> categoryClass, String name,
XContentParser parser, C context) throws IOException;
/**
* Get all entries for a specific category
* @param categoryClass category class
* @return list of entries for the category
*/
public List<Entry> getRegistry(Class<?> categoryClass);
}Usage Examples:
// Define parseable objects
public abstract class Query {
public abstract String getName();
}
public class MatchQuery extends Query {
private final String field;
private final String value;
public MatchQuery(String field, String value) {
this.field = field;
this.value = value;
}
public String getName() { return "match"; }
public static MatchQuery fromXContent(XContentParser parser) throws IOException {
// Parse match query from XContent
String field = null;
String value = null;
while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
if (parser.currentToken() == XContentParser.Token.FIELD_NAME) {
field = parser.currentName();
parser.nextToken();
value = parser.text();
}
}
return new MatchQuery(field, value);
}
}
// Create registry entries
List<NamedXContentRegistry.Entry> entries = Arrays.asList(
new NamedXContentRegistry.Entry(Query.class, new ParseField("match"),
(parser, context) -> MatchQuery.fromXContent(parser)),
new NamedXContentRegistry.Entry(Query.class, new ParseField("term"),
(parser, context) -> TermQuery.fromXContent(parser))
);
NamedXContentRegistry registry = new NamedXContentRegistry(entries);
// Parse named objects
String queryJson = """
{
"match": {
"title": "elasticsearch"
}
}
""";
XContentParser parser = XContentType.JSON.xContent()
.createParser(XContentParserConfiguration.EMPTY.withRegistry(registry), queryJson);
parser.nextToken(); // START_OBJECT
parser.nextToken(); // FIELD_NAME ("match")
String queryType = parser.currentName();
parser.nextToken(); // START_OBJECT (query content)
Query query = registry.parseNamedObject(Query.class, queryType, parser, null);Interface for handling deprecated field usage and API warnings.
/**
* Interface for handling deprecated content warnings
*/
public interface DeprecationHandler {
/**
* Handler that throws UnsupportedOperationException on any deprecation
*/
DeprecationHandler THROW_UNSUPPORTED_OPERATION = new DeprecationHandler() {
@Override
public void logRenamedField(String parserName, Supplier<XContentLocation> location,
String oldName, String currentName) {
throw new UnsupportedOperationException("Deprecated field [" + oldName + "] used");
}
@Override
public void logReplacedField(String parserName, Supplier<XContentLocation> location,
String oldName, String replacedName) {
throw new UnsupportedOperationException("Deprecated field [" + oldName + "] used");
}
@Override
public void logRemovedField(String parserName, Supplier<XContentLocation> location,
String removedName) {
throw new UnsupportedOperationException("Deprecated field [" + removedName + "] used");
}
};
/**
* Handler that ignores all deprecation warnings
*/
DeprecationHandler IGNORE_DEPRECATIONS = new DeprecationHandler() {
@Override
public void logRenamedField(String parserName, Supplier<XContentLocation> location,
String oldName, String currentName) {
// Ignore
}
@Override
public void logReplacedField(String parserName, Supplier<XContentLocation> location,
String oldName, String replacedName) {
// Ignore
}
@Override
public void logRemovedField(String parserName, Supplier<XContentLocation> location,
String removedName) {
// Ignore
}
};
/**
* Log usage of a renamed field
* @param parserName name of the parser detecting the deprecation
* @param location supplier for the location in content
* @param oldName deprecated field name that was used
* @param currentName current preferred field name
*/
void logRenamedField(String parserName, Supplier<XContentLocation> location,
String oldName, String currentName);
/**
* Log usage of a replaced field
* @param parserName name of the parser detecting the deprecation
* @param location supplier for the location in content
* @param oldName deprecated field name that was used
* @param replacedName name of the field that replaced it
*/
void logReplacedField(String parserName, Supplier<XContentLocation> location,
String oldName, String replacedName);
/**
* Log usage of a removed field
* @param parserName name of the parser detecting the deprecation
* @param location supplier for the location in content
* @param removedName name of the removed field
*/
void logRemovedField(String parserName, Supplier<XContentLocation> location, String removedName);
}Field definition with deprecation support for backward compatibility.
/**
* Represents a field name with support for deprecated alternatives
*/
public class ParseField {
/**
* Common field definitions used across the codebase
*/
public static class CommonFields {
public static final ParseField TYPE = new ParseField("type");
public static final ParseField VALUE = new ParseField("value");
public static final ParseField FORMAT = new ParseField("format");
// ... other common fields
}
/**
* Create a parse field with deprecated alternatives
* @param name preferred field name
* @param deprecatedNames deprecated field names that should still be accepted
*/
public ParseField(String name, String... deprecatedNames);
/**
* Get the preferred field name
* @return preferred name
*/
public String getPreferredName();
/**
* Get all valid names including deprecated ones
* @return array of all valid names
*/
public String[] getAllNamesIncludedDeprecated();
/**
* Check if a field name matches this parse field
* @param fieldName field name to check
* @param handler deprecation handler for warnings
* @return true if field name matches
*/
public boolean match(String fieldName, DeprecationHandler handler);
/**
* Create new parse field with additional deprecated names
* @param deprecatedNames additional deprecated names
* @return new ParseField with additional deprecations
*/
public ParseField withDeprecation(String... deprecatedNames);
/**
* Mark all names as deprecated in favor of replacement
* @param replacement replacement field name
* @return new ParseField with all names deprecated
*/
public ParseField withAllDeprecated(String replacement);
}Usage Examples:
// Define fields with deprecation support
ParseField nameField = new ParseField("name", "title", "label"); // name preferred, others deprecated
ParseField activeField = new ParseField("active", "enabled"); // active preferred, enabled deprecated
// Use in object parser
ObjectParser<User, Void> parser = new ObjectParser<>("user", User::new);
parser.declareString(User::setName, nameField);
parser.declareBoolean(User::setActive, activeField);
// Configure deprecation handling
XContentParserConfiguration config = XContentParserConfiguration.EMPTY
.withDeprecationHandler(DeprecationHandler.IGNORE_DEPRECATIONS);
// Parse content with deprecated field names
String jsonWithDeprecated = """
{
"title": "John Doe", // Will trigger deprecation warning
"enabled": true // Will trigger deprecation warning
}
""";
XContentParser contentParser = XContentType.JSON.xContent()
.createParser(config, jsonWithDeprecated);
User user = parser.parse(contentParser, null);Utility for navigating nested object structures using dot notation.
/**
* Utility class for evaluating object paths using dot notation
*/
public final class ObjectPath {
/**
* Evaluate a dot-separated path on an object
* @param path dot-separated path (e.g., "user.address.street")
* @param object root object to navigate
* @return value at the specified path, or null if not found
*/
public static <T> T eval(String path, Object object);
/**
* Evaluate a path array on an object
* @param path array of path segments
* @param object root object to navigate
* @return value at the specified path, or null if not found
*/
public static <T> T eval(String[] path, Object object);
}Usage Examples:
// Navigate nested structures
Map<String, Object> data = Map.of(
"user", Map.of(
"name", "John Doe",
"address", Map.of(
"street", "123 Main St",
"city", "New York"
)
)
);
// Extract nested values
String name = ObjectPath.eval("user.name", data); // "John Doe"
String street = ObjectPath.eval("user.address.street", data); // "123 Main St"
String missing = ObjectPath.eval("user.phone", data); // null
// Using path arrays
String city = ObjectPath.eval(new String[]{"user", "address", "city"}, data); // "New York"Install with Tessl CLI
npx tessl i tessl/maven-org-elasticsearch--elasticsearch-x-content