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 a comprehensive declarative framework for converting structured content directly into Java objects with type safety and flexible construction patterns.
Declarative, stateless parser for objects that use setter methods or field assignment.
/**
* Declarative parser for objects with setter-based construction
* @param <Value> the type of object to parse
* @param <Context> the type of parsing context
*/
public final class ObjectParser<Value, Context> extends AbstractObjectParser<Value, Context> {
/**
* Create an object parser with automatic value creation
* @param name parser name for error messages
*/
public ObjectParser(String name);
/**
* Create an object parser with custom value supplier
* @param name parser name for error messages
* @param valueSupplier supplier to create new instances
*/
public ObjectParser(String name, Supplier<Value> valueSupplier);
/**
* Create an object parser with unknown field handling
* @param name parser name for error messages
* @param ignoreUnknownFields whether to ignore unknown fields
* @param valueSupplier supplier to create new instances
*/
public ObjectParser(String name, boolean ignoreUnknownFields, Supplier<Value> valueSupplier);
/**
* Parse content into a new object instance
* @param parser content parser
* @param context parsing context
* @return parsed object
*/
public Value parse(XContentParser parser, Context context) throws IOException;
/**
* Parse content into an existing object instance
* @param parser content parser
* @param value existing object to populate
* @param context parsing context
* @return the populated object
*/
public Value parse(XContentParser parser, Value value, Context context) throws IOException;
}Methods for declaring how to parse different field types.
/**
* Declare a string field
* @param consumer setter method reference
* @param field parse field definition
*/
public void declareString(BiConsumer<Value, String> consumer, ParseField field);
/**
* Declare an integer field
* @param consumer setter method reference
* @param field parse field definition
*/
public void declareInt(BiConsumer<Value, Integer> consumer, ParseField field);
/**
* Declare a long field
* @param consumer setter method reference
* @param field parse field definition
*/
public void declareLong(BiConsumer<Value, Long> consumer, ParseField field);
/**
* Declare a float field
* @param consumer setter method reference
* @param field parse field definition
*/
public void declareFloat(BiConsumer<Value, Float> consumer, ParseField field);
/**
* Declare a double field
* @param consumer setter method reference
* @param field parse field definition
*/
public void declareDouble(BiConsumer<Value, Double> consumer, ParseField field);
/**
* Declare a boolean field
* @param consumer setter method reference
* @param field parse field definition
*/
public void declareBoolean(BiConsumer<Value, Boolean> consumer, ParseField field);
/**
* Declare an object field
* @param consumer setter method reference
* @param parser parser for the object type
* @param field parse field definition
*/
public <T> void declareObject(BiConsumer<Value, T> consumer, ContextParser<Context, T> parser, ParseField field);
/**
* Declare an array of objects field
* @param consumer setter method reference
* @param parser parser for individual array elements
* @param field parse field definition
*/
public <T> void declareObjectArray(BiConsumer<Value, List<T>> consumer, ContextParser<Context, T> parser, ParseField field);
/**
* Declare a named object field (using registry)
* @param consumer setter method reference
* @param namedObjectParser parser for named objects
* @param field parse field definition
*/
public <T> void declareNamedObject(BiConsumer<Value, T> consumer,
NamedObjectParser<T, Context> namedObjectParser, ParseField field);
/**
* Declare an array of named objects field
* @param consumer setter method reference
* @param namedObjectParser parser for individual named objects
* @param field parse field definition
*/
public <T> void declareNamedObjects(BiConsumer<Value, List<T>> consumer,
NamedObjectParser<T, Context> namedObjectParser, ParseField field);
/**
* Declare a field that can contain any type of value
* @param consumer setter method reference
* @param field parse field definition
*/
public void declareField(BiConsumer<Value, Object> consumer, ContextParser<Context, Object> parser,
ParseField field, ValueType expectedValueType);Usage Example:
import org.elasticsearch.xcontent.*;
// Define a simple data class
public class User {
private String name;
private int age;
private boolean active;
private List<String> skills;
private Address address;
// Constructor, getters, and setters...
public User() {}
public void setName(String name) { this.name = name; }
public void setAge(int age) { this.age = age; }
public void setActive(boolean active) { this.active = active; }
public void setSkills(List<String> skills) { this.skills = skills; }
public void setAddress(Address address) { this.address = address; }
}
public class Address {
private String street;
private String city;
public Address() {}
public void setStreet(String street) { this.street = street; }
public void setCity(String city) { this.city = city; }
}
// Create parsers
ObjectParser<Address, Void> addressParser = new ObjectParser<>("address", Address::new);
addressParser.declareString(Address::setStreet, new ParseField("street"));
addressParser.declareString(Address::setCity, new ParseField("city"));
ObjectParser<User, Void> userParser = new ObjectParser<>("user", User::new);
userParser.declareString(User::setName, new ParseField("name"));
userParser.declareInt(User::setAge, new ParseField("age"));
userParser.declareBoolean(User::setActive, new ParseField("active"));
userParser.declareStringArray(User::setSkills, new ParseField("skills"));
userParser.declareObject(User::setAddress, addressParser, new ParseField("address"));
// Parse JSON content
String json = """
{
"name": "John Doe",
"age": 30,
"active": true,
"skills": ["Java", "Elasticsearch"],
"address": {
"street": "123 Main St",
"city": "New York"
}
}
""";
XContentParser parser = XContentType.JSON.xContent()
.createParser(XContentParserConfiguration.EMPTY, json);
User user = userParser.parse(parser, null);
parser.close();Parser for objects that require constructor arguments rather than setter methods.
/**
* Parser for objects requiring constructor arguments
* @param <Value> the type of object to construct
* @param <Context> the type of parsing context
*/
public final class ConstructingObjectParser<Value, Context> extends AbstractObjectParser<Value, Context> {
/**
* Create a constructing parser with simple builder function
* @param name parser name for error messages
* @param builder function that constructs objects from argument array
*/
public ConstructingObjectParser(String name, Function<Object[], Value> builder);
/**
* Create a constructing parser with context-aware builder function
* @param name parser name for error messages
* @param ignoreUnknownFields whether to ignore unknown fields
* @param builder function that constructs objects from arguments and context
*/
public ConstructingObjectParser(String name, boolean ignoreUnknownFields,
BiFunction<Object[], Context, Value> builder);
/**
* Mark a field as a required constructor argument
* @return BiConsumer that marks the field as a constructor argument
*/
public static <Value, FieldT> BiConsumer<Value, FieldT> constructorArg();
/**
* Mark a field as an optional constructor argument
* @return BiConsumer that marks the field as an optional constructor argument
*/
public static <Value, FieldT> BiConsumer<Value, FieldT> optionalConstructorArg();
/**
* Parse content into a new object instance
* @param parser content parser
* @param context parsing context
* @return constructed object
*/
public Value parse(XContentParser parser, Context context) throws IOException;
}Usage Example:
// Immutable data class with constructor
public class ImmutableUser {
private final String name;
private final int age;
private final boolean active;
private final List<String> skills;
public ImmutableUser(String name, int age, boolean active, List<String> skills) {
this.name = name;
this.age = age;
this.active = active;
this.skills = skills;
}
// Getters only...
}
// Create constructing parser
ConstructingObjectParser<ImmutableUser, Void> parser = new ConstructingObjectParser<>(
"immutable_user",
args -> new ImmutableUser(
(String) args[0], // name
(Integer) args[1], // age
(Boolean) args[2], // active
(List<String>) args[3] // skills
)
);
// Declare fields as constructor arguments
parser.declareString(constructorArg(), new ParseField("name"));
parser.declareInt(constructorArg(), new ParseField("age"));
parser.declareBoolean(constructorArg(), new ParseField("active"));
parser.declareStringArray(constructorArg(), new ParseField("skills"));
// Parse content
XContentParser contentParser = XContentType.JSON.xContent()
.createParser(XContentParserConfiguration.EMPTY, jsonContent);
ImmutableUser user = parser.parse(contentParser, null);
contentParser.close();Parser that uses reflection to call constructors with @ParserConstructor annotation.
/**
* Parser that uses reflection for object construction
* @param <Value> the type of object to instantiate
* @param <Context> the type of parsing context
*/
public class InstantiatingObjectParser<Value, Context>
implements BiFunction<XContentParser, Context, Value>, ContextParser<Context, Value> {
/**
* Builder for creating instantiating parsers
*/
public static class Builder<Value, Context> {
/**
* Create a builder for the specified class
* @param name parser name for error messages
* @param valueClass class to instantiate
* @return builder instance
*/
public static <Value, Context> Builder<Value, Context> builder(String name, Class<Value> valueClass);
/**
* Create a builder with unknown field handling
* @param name parser name for error messages
* @param ignoreUnknownFields whether to ignore unknown fields
* @param valueClass class to instantiate
* @return builder instance
*/
public static <Value, Context> Builder<Value, Context> builder(String name, boolean ignoreUnknownFields,
Class<Value> valueClass);
/**
* Build the parser
* @return InstantiatingObjectParser instance
*/
public InstantiatingObjectParser<Value, Context> build();
}
/**
* Parse content and instantiate object
* @param parser content parser
* @param context parsing context
* @return instantiated object
*/
public Value apply(XContentParser parser, Context context);
}
/**
* Annotation to mark constructors for automatic parsing
*/
@Target(ElementType.CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParserConstructor {
}Usage Example:
// Data class with annotated constructor
public class AnnotatedUser {
private final String name;
private final int age;
private final boolean active;
@ParserConstructor
public AnnotatedUser(String name, int age, boolean active) {
this.name = name;
this.age = age;
this.active = active;
}
// Getters...
}
// Create instantiating parser
InstantiatingObjectParser<AnnotatedUser, Void> parser =
InstantiatingObjectParser.builder("annotated_user", AnnotatedUser.class).build();
// Parse content (field names must match constructor parameter names)
XContentParser contentParser = XContentType.JSON.xContent()
.createParser(XContentParserConfiguration.EMPTY, jsonContent);
AnnotatedUser user = parser.apply(contentParser, null);
contentParser.close();Enumeration defining supported value types for field declarations.
/**
* Enumeration of supported value types for object parsing
*/
public enum ValueType {
STRING,
STRING_OR_NULL,
FLOAT,
FLOAT_OR_NULL,
DOUBLE,
DOUBLE_OR_NULL,
INT,
INT_OR_NULL,
LONG,
LONG_OR_NULL,
BOOLEAN,
BOOLEAN_OR_NULL,
STRING_ARRAY,
FLOAT_ARRAY,
DOUBLE_ARRAY,
INT_ARRAY,
LONG_ARRAY,
BOOLEAN_ARRAY,
OBJECT,
OBJECT_OR_NULL,
OBJECT_ARRAY,
OBJECT_ARRAY_OR_NULL,
VALUE,
VALUE_OR_NULL,
VALUE_ARRAY
}/**
* Interface for parsing objects with context
*/
@FunctionalInterface
public interface ContextParser<Context, T> {
/**
* Parse an object with the given context
* @param parser content parser
* @param context parsing context
* @return parsed object
*/
T parse(XContentParser parser, Context context) throws IOException;
}
/**
* Interface for parsing named objects
*/
public interface NamedObjectParser<T, Context> {
/**
* Parse a named object
* @param parser content parser
* @param context parsing context
* @param name object name
* @return parsed object
*/
T parse(XContentParser parser, Context context, String name) throws IOException;
}
/**
* Interface for consuming unknown fields during parsing
*/
@FunctionalInterface
public interface UnknownFieldConsumer<Value> {
/**
* Accept an unknown field
* @param objectParser the parser that encountered the unknown field
* @param value the object being parsed
* @param fieldName the unknown field name
* @param parser content parser positioned at the field value
*/
void accept(ObjectParser<Value, ?> objectParser, Value value, String fieldName, XContentParser parser);
}Install with Tessl CLI
npx tessl i tessl/maven-org-elasticsearch--elasticsearch-x-content