Elasticsearch geometry library providing core geometric shapes and spatial utility classes for geometric computations and operations.
—
The Elasticsearch Geo library provides a pluggable validation framework for ensuring geometric validity. The framework supports different validation strategies including standard geometric validation and geography-specific validation with latitude/longitude bounds checking.
The core validation interface that defines the contract for geometry validation.
/**
* Generic geometry validator interface for verifying geometry validity
*/
public interface GeometryValidator {
/**
* No-operation validator that performs no validation
*/
public static final GeometryValidator NOOP = (geometry) -> {};
/**
* Validates the geometry and throws IllegalArgumentException if invalid
* @param geometry the geometry to validate
* @throws IllegalArgumentException if geometry is not valid
*/
void validate(Geometry geometry);
}
// Usage pattern:
GeometryValidator validator = new SomeValidator();
try {
validator.validate(geometry);
// Geometry is valid
} catch (IllegalArgumentException e) {
// Geometry is invalid, handle error
System.err.println("Invalid geometry: " + e.getMessage());
}Performs Z-coordinate validation based on the ignoreZValue parameter setting.
/**
* Standard validator that checks Z-coordinate usage constraints
* - Validates that Z coordinates are only present when ignoreZValue is true
* - Ensures consistent Z-dimension handling across geometry processing
*/
public class StandardValidator implements GeometryValidator {
/**
* Gets a StandardValidator instance with specified Z-value handling
* @param ignoreZValue whether to allow Z coordinates in geometries
* @return validator instance (cached for performance)
*/
public static GeometryValidator instance(boolean ignoreZValue)
/**
* Validates geometry according to Z-coordinate constraints
* @param geometry the geometry to validate
* @throws IllegalArgumentException if geometry has Z values when ignoreZValue is false
*/
@Override
public void validate(Geometry geometry)
/**
* Checks individual Z coordinate values
* @param zValue the Z coordinate to check
* @throws IllegalArgumentException if Z value is present and ignoreZValue is false
*/
protected void checkZ(double zValue)
}
// Validation rules applied by StandardValidator:
// - When ignoreZValue is false: Throws exception if any geometry has Z coordinates
// - When ignoreZValue is true: Allows Z coordinates without validation
// - Uses visitor pattern to recursively check all geometry components
// - Provides static factory method for cached instancesValidates geometries for geographic coordinate systems with latitude/longitude bounds checking.
/**
* Geography-specific validator that checks coordinate bounds and geographic constraints
* - Validates latitude values are within [-90, 90] degrees
* - Validates longitude values are within [-180, 180] degrees
* - Validates Z-coordinate usage according to ignoreZValue setting
* - Applies standard validation rules plus geographic constraints
*/
public class GeographyValidator implements GeometryValidator {
/**
* Minimum longitude value (inclusive)
*/
private static final double MIN_LON_INCL = -180.0D;
/**
* Maximum longitude value (inclusive)
*/
private static final double MAX_LON_INCL = 180.0D;
/**
* Minimum latitude value (inclusive)
*/
private static final double MIN_LAT_INCL = -90.0D;
/**
* Maximum latitude value (inclusive)
*/
private static final double MAX_LAT_INCL = 90.0D;
/**
* Gets a GeographyValidator instance with specified Z-value handling
* @param ignoreZValue whether to allow Z coordinates in geometries
* @return validator instance (cached for performance)
*/
public static GeometryValidator instance(boolean ignoreZValue)
/**
* Validates geometry according to geographic coordinate constraints
* @param geometry the geometry to validate
* @throws IllegalArgumentException if geometry violates geographic constraints
*/
@Override
public void validate(Geometry geometry)
/**
* Validates latitude value is within standard bounds
* @param latitude the latitude value to check
* @throws IllegalArgumentException if latitude is outside [-90, 90] range
*/
protected void checkLatitude(double latitude)
/**
* Validates longitude value is within standard bounds
* @param longitude the longitude value to check
* @throws IllegalArgumentException if longitude is outside [-180, 180] range
*/
protected void checkLongitude(double longitude)
/**
* Validates altitude value according to ignoreZValue setting
* @param zValue the altitude value to check
* @throws IllegalArgumentException if altitude is present when ignoreZValue is false
*/
protected void checkAltitude(double zValue)
}
// Additional validation rules for GeographyValidator:
// - Latitude coordinates must be in range [-90.0, 90.0]
// - Longitude coordinates must be in range [-180.0, 180.0]
// - Altitude values should be reasonable (typically above -11000m, below 9000m)
// - Circle radius should be reasonable for geographic scales
// - Rectangle bounds should respect geographic coordinate limitsA validator that performs no validation, useful for performance-critical scenarios or trusted data.
// Built-in no-op validator constant
GeometryValidator noopValidator = GeometryValidator.NOOP;
// No validation is performed - geometry is assumed to be valid
noopValidator.validate(anyGeometry); // Never throws exceptions
// Useful for:
// - Performance-critical applications where validation overhead is unacceptable
// - Processing trusted geometry data that is known to be valid
// - Testing scenarios where validation behavior should be bypassedThe WKT parser integrates with the validation framework to ensure parsed geometries are valid.
import org.elasticsearch.geometry.utils.WellKnownText;
// Parse WKT with validation
GeometryValidator validator = new StandardValidator();
String wkt = "POINT(-73.935242 40.730610)";
try {
Geometry geometry = WellKnownText.fromWKT(validator, false, wkt);
// Geometry is valid and ready to use
} catch (IllegalArgumentException e) {
// Invalid geometry or validation failure
System.err.println("Validation failed: " + e.getMessage());
} catch (IOException | ParseException e) {
// WKT parsing error
System.err.println("Parse error: " + e.getMessage());
}
// Parse with coercion and validation
try {
// Coercion attempts to fix minor issues (e.g., auto-close polygons)
Geometry coerced = WellKnownText.fromWKT(validator, true, wkt);
} catch (Exception e) {
System.err.println("Coercion and validation failed: " + e.getMessage());
}Create custom validators for specific application requirements.
/**
* Example custom validator that enforces application-specific constraints
*/
public class ApplicationValidator implements GeometryValidator {
private final double maxAllowedRadius;
private final Rectangle allowedBounds;
private final GeometryValidator baseValidator;
public ApplicationValidator(double maxRadius, Rectangle bounds) {
this.maxAllowedRadius = maxRadius;
this.allowedBounds = bounds;
this.baseValidator = new StandardValidator();
}
@Override
public void validate(Geometry geometry) {
// First apply standard validation
baseValidator.validate(geometry);
// Then apply custom rules using visitor pattern
geometry.visit(new GeometryVisitor<Void, IllegalArgumentException>() {
@Override
public Void visit(Circle circle) {
if (circle.getRadiusMeters() > maxAllowedRadius) {
throw new IllegalArgumentException(
"Circle radius " + circle.getRadiusMeters() +
" exceeds maximum allowed " + maxAllowedRadius);
}
validateWithinBounds(circle.getX(), circle.getY());
return null;
}
@Override
public Void visit(Point point) {
validateWithinBounds(point.getX(), point.getY());
return null;
}
@Override
public Void visit(Rectangle rectangle) {
validateWithinBounds(rectangle.getMinX(), rectangle.getMinY());
validateWithinBounds(rectangle.getMaxX(), rectangle.getMaxY());
return null;
}
// ... implement other visit methods
private void validateWithinBounds(double x, double y) {
if (x < allowedBounds.getMinX() || x > allowedBounds.getMaxX() ||
y < allowedBounds.getMinY() || y > allowedBounds.getMaxY()) {
throw new IllegalArgumentException(
"Coordinate (" + x + ", " + y + ") is outside allowed bounds");
}
}
});
}
}Use comprehensive validation for data integrity in critical applications.
// Strict validation with geographic constraints
GeometryValidator strictValidator = new GeographyValidator();
// Validate all geometries before processing
public void processGeometry(Geometry geometry) {
strictValidator.validate(geometry);
// Proceed with processing - geometry is guaranteed valid
String wkt = WellKnownText.toWKT(geometry);
// ... additional processing
}
// Chain validators for multiple validation levels
public class ChainedValidator implements GeometryValidator {
private final List<GeometryValidator> validators;
public ChainedValidator(GeometryValidator... validators) {
this.validators = Arrays.asList(validators);
}
@Override
public void validate(Geometry geometry) {
for (GeometryValidator validator : validators) {
validator.validate(geometry);
}
}
}
// Use chained validation
GeometryValidator chainedValidator = new ChainedValidator(
StandardValidator.instance(true),
new GeographyValidator(),
new ApplicationValidator(10000.0, worldBounds)
);Skip validation for performance-critical scenarios with trusted data.
// No validation for maximum performance
GeometryValidator noValidation = GeometryValidator.NOOP;
// High-performance batch processing
public void processBatch(List<Geometry> geometries) {
for (Geometry geometry : geometries) {
// Skip validation for trusted data
noValidation.validate(geometry); // No-op
// Direct processing
processGeometryDirectly(geometry);
}
}
// Conditional validation based on data source
public void processGeometry(Geometry geometry, boolean trusted) {
GeometryValidator validator = trusted ?
GeometryValidator.NOOP :
StandardValidator.instance(true);
validator.validate(geometry);
// ... process geometry
}import org.elasticsearch.geometry.*;
import org.elasticsearch.geometry.utils.*;
// Create geometries
Point validPoint = new Point(-73.935242, 40.730610);
Point invalidLatPoint = new Point(-73.935242, 95.0); // Invalid latitude > 90
Circle negativeRadius = new Circle(-73.935242, 40.730610, -100.0); // Invalid negative radius
// Standard validation
GeometryValidator standardValidator = StandardValidator.instance(false);
try {
standardValidator.validate(validPoint); // Passes
System.out.println("Point is valid");
} catch (IllegalArgumentException e) {
System.err.println("Point validation failed: " + e.getMessage());
}
try {
standardValidator.validate(negativeRadius); // Fails - negative radius
} catch (IllegalArgumentException e) {
System.err.println("Circle validation failed: " + e.getMessage());
}
// Geography validation
GeometryValidator geoValidator = new GeographyValidator();
try {
geoValidator.validate(invalidLatPoint); // Fails - latitude out of bounds
} catch (IllegalArgumentException e) {
System.err.println("Geography validation failed: " + e.getMessage());
}import org.elasticsearch.geometry.utils.WellKnownText;
GeometryValidator validator = StandardValidator.instance(true);
// Valid WKT
String validWkt = "POINT(-73.935242 40.730610)";
try {
Geometry geometry = WellKnownText.fromWKT(validator, false, validWkt);
System.out.println("Parsed valid geometry: " + geometry.type());
} catch (Exception e) {
System.err.println("Failed to parse: " + e.getMessage());
}
// Invalid WKT (unclosed polygon)
String invalidWkt = "POLYGON((-74.0 40.7,-73.9 40.7,-73.9 40.8))"; // Missing closing point
try {
// Without coercion - should fail
Geometry geometry = WellKnownText.fromWKT(validator, false, invalidWkt);
} catch (Exception e) {
System.err.println("Validation failed: " + e.getMessage());
}
try {
// With coercion - attempts to fix by auto-closing
Geometry geometry = WellKnownText.fromWKT(validator, true, invalidWkt);
System.out.println("Coerced geometry is valid");
} catch (Exception e) {
System.err.println("Coercion failed: " + e.getMessage());
}// Define application bounds (e.g., continental US)
Rectangle usBounds = new Rectangle(-125.0, -66.0, 49.0, 24.0);
// Create custom validator with application constraints
ApplicationValidator appValidator = new ApplicationValidator(50000.0, usBounds);
// Test geometries
Point validUSPoint = new Point(-100.0, 40.0); // Inside US bounds
Point invalidUSPoint = new Point(0.0, 0.0); // Outside US bounds (null island)
Circle largeCirle = new Circle(-100.0, 40.0, 100000.0); // Too large radius
try {
appValidator.validate(validUSPoint); // Passes
System.out.println("US point is valid");
} catch (IllegalArgumentException e) {
System.err.println("US validation failed: " + e.getMessage());
}
try {
appValidator.validate(invalidUSPoint); // Fails - outside bounds
} catch (IllegalArgumentException e) {
System.err.println("Point outside US bounds: " + e.getMessage());
}
try {
appValidator.validate(largeCirle); // Fails - radius too large
} catch (IllegalArgumentException e) {
System.err.println("Circle too large: " + e.getMessage());
}Install with Tessl CLI
npx tessl i tessl/maven-org-elasticsearch--elasticsearch-geo