Grid9 Java Implementation
The Java implementation of Grid9 provides enterprise-grade coordinate compression for JVM-based applications. With comprehensive JUnit test coverage and Java 8+ compatibility, it's perfect for Spring Boot applications, microservices, and large-scale distributed systems.
Key Features: Java 8+ compatible • Maven Central ready • Spring Boot integration • Thread-safe operations • Comprehensive JUnit tests • Zero external dependencies
Installation
Maven
<dependency>
<groupId>com.grid9</groupId>
<artifactId>grid9-java</artifactId>
<version>1.0.0</version>
</dependency>
Gradle
// Gradle (Groovy)
implementation 'com.grid9:grid9-java:1.0.0'
// Gradle (Kotlin DSL)
implementation("com.grid9:grid9-java:1.0.0")
From Source
git clone https://github.com/pedrof69/Grid9.git
cd Grid9/java
mvn clean install
Quick Start
Basic Usage
import com.grid9.UniformPrecisionCoordinateCompressor;
public class LocationExample {
public static void main(String[] args) {
// Encode coordinates to Grid9 code
String code = UniformPrecisionCoordinateCompressor.encode(40.7128, -74.0060);
System.out.println(code); // "Q7KH2BBYF"
// Decode Grid9 code to coordinates
double[] coords = UniformPrecisionCoordinateCompressor.decode("Q7KH2BBYF");
System.out.println("Lat: " + coords[0] + ", Lon: " + coords[1]);
// Result: Lat: 40.712779, Lon: -74.005988
// Human-readable format
String readable = UniformPrecisionCoordinateCompressor.encode(40.7128, -74.0060, true);
System.out.println(readable); // "Q7K-H2B-BYF"
}
}
Spring Boot Integration
@RestController
@RequestMapping("/api/location")
public class LocationController {
@PostMapping("/encode")
public ResponseEntity<Map<String, String>> encodeCoordinates(
@RequestBody CoordinateRequest request) {
try {
String code = UniformPrecisionCoordinateCompressor.encode(
request.getLatitude(),
request.getLongitude()
);
return ResponseEntity.ok(Map.of("grid9Code", code));
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest()
.body(Map.of("error", e.getMessage()));
}
}
@GetMapping("/decode/{code}")
public ResponseEntity<CoordinateResponse> decodeGrid9(
@PathVariable String code) {
try {
double[] coords = UniformPrecisionCoordinateCompressor.decode(code);
return ResponseEntity.ok(new CoordinateResponse(coords[0], coords[1]));
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().build();
}
}
}
Stream Processing
import java.util.stream.Collectors;
import com.grid9.CoordinateOperations;
public class LocationProcessor {
public List<String> processLocationStream(List<Location> locations) {
return locations.stream()
.filter(loc -> loc.getLatitude() != 0 && loc.getLongitude() != 0)
.map(loc -> UniformPrecisionCoordinateCompressor.encode(
loc.getLatitude(), loc.getLongitude()))
.distinct()
.collect(Collectors.toList());
}
// Parallel processing for large datasets
public List<String> processLargeDataset(List<Location> locations) {
return locations.parallelStream()
.map(this::encodeLocation)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
private String encodeLocation(Location loc) {
try {
return UniformPrecisionCoordinateCompressor.encode(
loc.getLatitude(), loc.getLongitude());
} catch (IllegalArgumentException e) {
return null; // Skip invalid coordinates
}
}
}
API Reference
UniformPrecisionCoordinateCompressor
| Method | Description | Returns |
|---|---|---|
encode(double lat, double lon) |
Encode coordinates to Grid9 code | String |
encode(double lat, double lon, boolean humanReadable) |
Encode with optional formatting | String |
decode(String code) |
Decode Grid9 code to coordinates | double[] {lat, lon} |
calculateDistance(String code1, String code2) |
Calculate distance in meters | double |
getNeighbors(String code) |
Get adjacent Grid9 codes | List<String> |
isValidEncoding(String code) |
Validate Grid9 code format | boolean |
getActualPrecision(double lat, double lon) |
Get precision information | double[] {x, y, total} |
CoordinateOperations
| Method | Description | Returns |
|---|---|---|
batchEncode(List<double[]> coordinates) |
Encode multiple coordinates | List<String> |
batchDecode(List<String> codes) |
Decode multiple codes | List<double[]> |
findNearby(double lat, double lon, double radius) |
Find codes within radius | List<String> |
Enterprise Integration
JPA Entity Integration
@Entity
@Table(name = "locations")
public class LocationEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "latitude")
private Double latitude;
@Column(name = "longitude")
private Double longitude;
// Computed property for Grid9 code
@Transient
public String getGrid9Code() {
if (latitude != null && longitude != null) {
return UniformPrecisionCoordinateCompressor.encode(latitude, longitude);
}
return null;
}
// Static method to create from Grid9 code
public static LocationEntity fromGrid9(String code, String name) {
double[] coords = UniformPrecisionCoordinateCompressor.decode(code);
LocationEntity entity = new LocationEntity();
entity.setName(name);
entity.setLatitude(coords[0]);
entity.setLongitude(coords[1]);
return entity;
}
}
Spring Data Repository
@Repository
public interface LocationRepository extends JpaRepository<LocationEntity, Long> {
@Query("SELECT l FROM LocationEntity l WHERE " +
"ABS(l.latitude - :lat) < :delta AND ABS(l.longitude - :lon) < :delta")
List<LocationEntity> findNearby(@Param("lat") double latitude,
@Param("lon") double longitude,
@Param("delta") double delta);
}
@Service
public class LocationService {
@Autowired
private LocationRepository repository;
public List<String> findNearbyGrid9Codes(double lat, double lon, double radiusMeters) {
// Convert radius to approximate degree delta (rough approximation)
double delta = radiusMeters / 111000.0; // 1 degree ≈ 111km
return repository.findNearby(lat, lon, delta)
.stream()
.map(LocationEntity::getGrid9Code)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}
Apache Kafka Integration
@Component
public class LocationEventProcessor {
@EventListener
public void handleLocationUpdate(LocationUpdateEvent event) {
String grid9Code = UniformPrecisionCoordinateCompressor.encode(
event.getLatitude(), event.getLongitude());
// Send to Kafka topic with Grid9 code as key for partitioning
kafkaTemplate.send("location-updates", grid9Code, event);
}
@KafkaListener(topics = "location-updates")
public void processLocationEvent(
@Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) String grid9Code,
LocationUpdateEvent event) {
// Process events grouped by Grid9 location
double[] coords = UniformPrecisionCoordinateCompressor.decode(grid9Code);
processLocationCluster(coords[0], coords[1], event);
}
}
Performance
Encoding Speed
4.8M+ operations/second
Decoding Speed
5.2M+ operations/second
Memory Usage
Minimal heap allocation
Performance Tuning
// For high-throughput applications, consider caching
public class CachedGrid9Encoder {
private final LRUCache<String, String> encodeCache = new LRUCache<>(10000);
private final LRUCache<String, double[]> decodeCache = new LRUCache<>(10000);
public String encode(double lat, double lon) {
String key = lat + "," + lon;
return encodeCache.computeIfAbsent(key, k ->
UniformPrecisionCoordinateCompressor.encode(lat, lon));
}
public double[] decode(String code) {
return decodeCache.computeIfAbsent(code,
UniformPrecisionCoordinateCompressor::decode);
}
}
Advanced Features
Geospatial Analysis
public class GeospatialAnalyzer {
public Map<String, Integer> analyzeLocationDensity(List<Location> locations) {
return locations.stream()
.collect(Collectors.groupingBy(
loc -> UniformPrecisionCoordinateCompressor.encode(
loc.getLatitude(), loc.getLongitude()),
Collectors.collectingAndThen(
Collectors.counting(),
Math::toIntExact
)
));
}
public List<String> findLocationClusters(List<Location> locations,
int minClusterSize) {
Map<String, Integer> density = analyzeLocationDensity(locations);
return density.entrySet().stream()
.filter(entry -> entry.getValue() >= minClusterSize)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
}
Microservice Communication
@RestTemplate
public class LocationServiceClient {
@Autowired
private RestTemplate restTemplate;
public List<String> getNearbyServices(double lat, double lon, double radius) {
String grid9Code = UniformPrecisionCoordinateCompressor.encode(lat, lon);
// Use Grid9 code in service discovery
String url = "http://service-registry/api/services/nearby/" + grid9Code +
"?radius=" + radius;
ServiceResponse response = restTemplate.getForObject(url, ServiceResponse.class);
return response.getServiceEndpoints();
}
}
Validation and Error Handling
public class LocationValidator {
public static class ValidationResult {
private final boolean valid;
private final String errorMessage;
// Constructor and getters...
}
public ValidationResult validateCoordinates(double lat, double lon) {
if (lat < -90 || lat > 90) {
return new ValidationResult(false,
"Latitude must be between -90 and 90 degrees");
}
if (lon < -180 || lon > 180) {
return new ValidationResult(false,
"Longitude must be between -180 and 180 degrees");
}
return new ValidationResult(true, null);
}
public ValidationResult validateGrid9Code(String code) {
if (!UniformPrecisionCoordinateCompressor.isValidEncoding(code)) {
return new ValidationResult(false, "Invalid Grid9 code format");
}
return new ValidationResult(true, null);
}
}
Testing
# Run all tests
mvn test
# Run tests with coverage
mvn test jacoco:report
# Run performance tests
mvn test -Pperformance
# Run specific test class
mvn test -Dtest=UniformPrecisionCoordinateCompressorTest
Requirements
- Java 8+ ✓
- Maven 3.6+ or Gradle 5+ for building
- No external runtime dependencies
- JUnit 5 for testing (test scope only)
Build and Deployment
Maven Build Lifecycle
# Clean and compile
mvn clean compile
# Run tests and package
mvn clean package
# Install to local repository
mvn clean install
# Deploy to Maven Central (requires credentials)
mvn clean deploy
Docker Integration
# Dockerfile for Spring Boot app with Grid9
FROM openjdk:11-jre-slim
COPY target/my-location-app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
# Build and run
docker build -t my-location-app .
docker run -p 8080:8080 my-location-app
Need help? Check out the full source code and examples on GitHub or open an issue.