/**
* POST TITLE: Spring Cloud Contract - Consumer-Driven Contracts in Java
*
* Complete implementation of contract testing with Spring Cloud Contract
*/
import org.springframework.cloud.contract.spec.Contract;
import org.springframework.cloud.contract.verifier.messaging.ContractVerifierMessaging;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper;
import org.springframework.cloud.contract.wiremock.WireMockRestServiceServer;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.*;
import java.util.function.Supplier;
public class SpringCloudContractDemo {
/**
* Producer Side - User Service (Provider)
*/
public static class User {
private Long id;
private String name;
private String email;
private String status;
private Date createdAt;
public User() {}
public User(Long id, String name, String email, String status) {
this.id = id;
this.name = name;
this.email = email;
this.status = status;
this.createdAt = new Date();
}
// Getters and setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public Date getCreatedAt() { return createdAt; }
public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }
}
/**
* User Service Controller (Producer)
*/
@RestController
@RequestMapping("/api/users")
public static class UserController {
private final UserService userService;
private final ObjectMapper objectMapper;
public UserController(UserService userService, ObjectMapper objectMapper) {
this.userService = userService;
this.objectMapper = objectMapper;
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
try {
User user = userService.findById(id);
if (user != null) {
return ResponseEntity.ok(user);
} else {
return ResponseEntity.notFound().build();
}
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@GetMapping
public ResponseEntity<List<User>> getAllUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
try {
List<User> users = userService.findAll(page, size);
return ResponseEntity.ok(users);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
try {
User created = userService.create(user);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
try {
User updated = userService.update(id, user);
if (updated != null) {
return ResponseEntity.ok(updated);
} else {
return ResponseEntity.notFound().build();
}
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
try {
boolean deleted = userService.delete(id);
if (deleted) {
return ResponseEntity.noContent().build();
} else {
return ResponseEntity.notFound().build();
}
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
/**
* User Service Business Logic
*/
@Service
public static class UserService {
private final Map<Long, User> userRepository = new HashMap<>();
private long currentId = 1;
public User findById(Long id) {
return userRepository.get(id);
}
public List<User> findAll(int page, int size) {
return userRepository.values().stream()
.skip(page * size)
.limit(size)
.collect(Collectors.toList());
}
public User create(User user) {
if (user.getName() == null || user.getEmail() == null) {
throw new IllegalArgumentException("Name and email are required");
}
user.setId(currentId++);
user.setStatus("ACTIVE");
user.setCreatedAt(new Date());
userRepository.put(user.getId(), user);
return user;
}
public User update(Long id, User userUpdates) {
User existing = userRepository.get(id);
if (existing == null) {
return null;
}
if (userUpdates.getName() != null) {
existing.setName(userUpdates.getName());
}
if (userUpdates.getEmail() != null) {
existing.setEmail(userUpdates.getEmail());
}
if (userUpdates.getStatus() != null) {
existing.setStatus(userUpdates.getStatus());
}
userRepository.put(id, existing);
return existing;
}
public boolean delete(Long id) {
return userRepository.remove(id) != null;
}
}
/**
* CONTRACT DEFINITIONS - Producer Side
* These contracts define the expected API behavior
*/
public static class UserServiceContracts {
/**
* Contract 1: Get user by ID (success case)
*/
public Contract shouldReturnUserWhenExists() {
return Contract.make(c -> {
c.description("Should return user when user exists");
c.name("get_user_by_id_success");
// Request
c.request(r -> {
r.method(r.GET());
r.url(r.$(r.regex("/api/users/[0-9]+"), "/api/users/1"));
r.headers(h -> {
h.contentType(h.applicationJson());
});
});
// Response
c.response(r -> {
r.status(r.OK());
r.headers(h -> {
h.contentType(h.applicationJson());
});
r.body(b -> {
b.$(b.regex(r.number()), 1L); // id
b.$(b.regex(r.nonEmpty())), "John Doe"); // name
b.$(b.regex(r.email())), "[email protected]"); // email
b.$(b.regex(r.anyOf("ACTIVE", "INACTIVE"))), "ACTIVE"); // status
b.$(b.regex(r.isoDate())), "2024-01-15T10:30:00.000Z"); // createdAt
});
});
c.priority(1);
});
}
/**
* Contract 2: Get user by ID (not found)
*/
public Contract shouldReturnNotFoundWhenUserDoesNotExist() {
return Contract.make(c -> {
c.description("Should return 404 when user does not exist");
c.name("get_user_by_id_not_found");
c.request(r -> {
r.method(r.GET());
r.url("/api/users/999");
});
c.response(r -> {
r.status(r.NOT_FOUND());
});
c.priority(2);
});
}
/**
* Contract 3: Create user (success)
*/
public Contract shouldCreateUserWhenValid() {
return Contract.make(c -> {
c.description("Should create user when valid data provided");
c.name("create_user_success");
c.request(r -> {
r.method(r.POST());
r.url("/api/users");
r.headers(h -> {
h.contentType(h.applicationJson());
});
r.body(b -> {
b.$(b.regex(r.nonEmpty())), "Jane Smith"); // name
b.$(b.regex(r.email())), "[email protected]"); // email
});
});
c.response(r -> {
r.status(r.CREATED());
r.headers(h -> {
h.contentType(h.applicationJson());
});
r.body(b -> {
b.$(b.regex(r.number())), 2L); // id
b.$(b.regex(r.nonEmpty())), "Jane Smith"); // name
b.$(b.regex(r.email())), "[email protected]"); // email
b.$(b.regex(r.anyOf("ACTIVE", "INACTIVE"))), "ACTIVE"); // status
b.$(b.regex(r.isoDate())), "2024-01-15T10:30:00.000Z"); // createdAt
});
});
c.priority(1);
});
}
/**
* Contract 4: Create user (validation error)
*/
public Contract shouldReturnBadRequestWhenInvalid() {
return Contract.make(c -> {
c.description("Should return 400 when invalid data provided");
c.name("create_user_validation_error");
c.request(r -> {
r.method(r.POST());
r.url("/api/users");
r.headers(h -> {
h.contentType(h.applicationJson());
});
r.body(b -> {
b.$(b.regex(r.anyOf(null, ""))), null); // name missing
b.$(b.regex(r.email())), "invalid-email"); // invalid email
});
});
c.response(r -> {
r.status(r.BAD_REQUEST());
});
c.priority(2);
});
}
/**
* Contract 5: Get all users with pagination
*/
public Contract shouldReturnPaginatedUsers() {
return Contract.make(c -> {
c.description("Should return paginated list of users");
c.name("get_all_users_paginated");
c.request(r -> {
r.method(r.GET());
r.url(r.$(r.regex("/api/users\\?page=[0-9]+&size=[0-9]+"), "/api/users?page=0&size=10"));
});
c.response(r -> {
r.status(r.OK());
r.headers(h -> {
h.contentType(h.applicationJson());
});
r.body(b -> {
b.$(b.regex(r.nonEmpty())), b.$(b.eachLike(b -> {
b.$(b.regex(r.number())), 1L);
b.$(b.regex(r.nonEmpty())), "John Doe");
b.$(b.regex(r.email())), "[email protected]");
b.$(b.regex(r.anyOf("ACTIVE", "INACTIVE"))), "ACTIVE");
b.$(b.regex(r.isoDate())), "2024-01-15T10:30:00.000Z");
})));
});
});
c.priority(2);
});
}
}
/**
* Consumer Side - Order Service
*/
public static class Order {
private Long id;
private Long userId;
private String product;
private BigDecimal amount;
private String status;
public Order() {}
public Order(Long id, Long userId, String product, BigDecimal amount, String status) {
this.id = id;
this.userId = userId;
this.product = product;
this.amount = amount;
this.status = status;
}
// Getters and setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public Long getUserId() { return userId; }
public void setUserId(Long userId) { this.userId = userId; }
public String getProduct() { return product; }
public void setProduct(String product) { this.product = product; }
public BigDecimal getAmount() { return amount; }
public void setAmount(BigDecimal amount) { this.amount = amount; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
}
/**
* Order Service that consumes User Service
*/
@Service
public static class OrderService {
private final RestTemplate restTemplate;
private final String userServiceUrl;
private final ObjectMapper objectMapper;
public OrderService(RestTemplate restTemplate,
@Value("${user.service.url:http://localhost:8080}") String userServiceUrl,
ObjectMapper objectMapper) {
this.restTemplate = restTemplate;
this.userServiceUrl = userServiceUrl;
this.objectMapper = objectMapper;
}
public Order createOrder(Long userId, String product, BigDecimal amount) {
// First, validate user exists and is active
User user = getUser(userId);
if (user == null) {
throw new UserNotFoundException("User not found: " + userId);
}
if (!"ACTIVE".equals(user.getStatus())) {
throw new UserInactiveException("User is inactive: " + userId);
}
// Create order
Order order = new Order();
order.setUserId(userId);
order.setProduct(product);
order.setAmount(amount);
order.setStatus("CREATED");
// Save order logic would go here
return order;
}
public User getUser(Long userId) {
try {
String url = userServiceUrl + "/api/users/" + userId;
ResponseEntity<User> response = restTemplate.getForEntity(url, User.class);
if (response.getStatusCode() == HttpStatus.OK) {
return response.getBody();
} else if (response.getStatusCode() == HttpStatus.NOT_FOUND) {
return null;
} else {
throw new UserServiceException("Unexpected response: " + response.getStatusCode());
}
} catch (Exception e) {
throw new UserServiceException("Failed to fetch user: " + e.getMessage(), e);
}
}
public List<User> getAllActiveUsers() {
try {
String url = userServiceUrl + "/api/users?page=0&size=100";
ResponseEntity<List<User>> response = restTemplate.exchange(
url, HttpMethod.GET, null,
new ParameterizedTypeReference<List<User>>() {}
);
if (response.getStatusCode() == HttpStatus.OK) {
return response.getBody().stream()
.filter(user -> "ACTIVE".equals(user.getStatus()))
.collect(Collectors.toList());
} else {
throw new UserServiceException("Failed to fetch users: " + response.getStatusCode());
}
} catch (Exception e) {
throw new UserServiceException("Failed to fetch active users: " + e.getMessage(), e);
}
}
}
/**
* Custom Exceptions
*/
public static class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) { super(message); }
}
public static class UserInactiveException extends RuntimeException {
public UserInactiveException(String message) { super(message); }
}
public static class UserServiceException extends RuntimeException {
public UserServiceException(String message) { super(message); }
public UserServiceException(String message, Throwable cause) { super(message, cause); }
}
/**
* CONSUMER TESTS - Generated from Contracts
*/
@SpringBootTest
@AutoConfigureWireMock(port = 0)
public static class OrderServiceConsumerTest {
@Autowired
private OrderService orderService;
@Autowired
private RestTemplate restTemplate;
@BeforeEach
public void setup() {
// WireMock will be auto-configured by @AutoConfigureWireMock
}
@Test
public void shouldCreateOrderForActiveUser() {
// Given: User exists and is active (mocked response)
stubFor(get(urlPathMatching("/api/users/1"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("""
{
"id": 1,
"name": "John Doe",
"email": "[email protected]",
"status": "ACTIVE",
"createdAt": "2024-01-15T10:30:00.000Z"
}
""")));
// When: Creating order for user
Order order = orderService.createOrder(1L, "Laptop", new BigDecimal("999.99"));
// Then: Order should be created successfully
assertThat(order).isNotNull();
assertThat(order.getUserId()).isEqualTo(1L);
assertThat(order.getProduct()).isEqualTo("Laptop");
assertThat(order.getStatus()).isEqualTo("CREATED");
// Verify the interaction happened
verify(getRequestedFor(urlPathMatching("/api/users/1")));
}
@Test
public void shouldFailWhenUserNotFound() {
// Given: User does not exist
stubFor(get(urlPathMatching("/api/users/999"))
.willReturn(aResponse()
.withStatus(404)));
// When/Then: Should throw UserNotFoundException
assertThatThrownBy(() ->
orderService.createOrder(999L, "Laptop", new BigDecimal("999.99")))
.isInstanceOf(UserNotFoundException.class)
.hasMessageContaining("User not found: 999");
verify(getRequestedFor(urlPathMatching("/api/users/999")));
}
@Test
public void shouldFailWhenUserInactive() {
// Given: User exists but is inactive
stubFor(get(urlPathMatching("/api/users/2"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("""
{
"id": 2,
"name": "Inactive User",
"email": "[email protected]",
"status": "INACTIVE",
"createdAt": "2024-01-15T10:30:00.000Z"
}
""")));
// When/Then: Should throw UserInactiveException
assertThatThrownBy(() ->
orderService.createOrder(2L, "Laptop", new BigDecimal("999.99")))
.isInstanceOf(UserInactiveException.class)
.hasMessageContaining("User is inactive: 2");
verify(getRequestedFor(urlPathMatching("/api/users/2")));
}
@Test
public void shouldGetAllActiveUsers() {
// Given: Multiple users exist
stubFor(get(urlPathMatching("/api/users.*"))
.withQueryParam("page", equalTo("0"))
.withQueryParam("size", equalTo("100"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("""
[
{
"id": 1,
"name": "Active User 1",
"email": "[email protected]",
"status": "ACTIVE",
"createdAt": "2024-01-15T10:30:00.000Z"
},
{
"id": 2,
"name": "Inactive User",
"email": "[email protected]",
"status": "INACTIVE",
"createdAt": "2024-01-15T10:30:00.000Z"
},
{
"id": 3,
"name": "Active User 2",
"email": "[email protected]",
"status": "ACTIVE",
"createdAt": "2024-01-15T10:30:00.000Z"
}
]
""")));
// When: Getting all active users
List<User> activeUsers = orderService.getAllActiveUsers();
// Then: Only active users should be returned
assertThat(activeUsers).hasSize(2);
assertThat(activeUsers)
.extracting(User::getStatus)
.containsOnly("ACTIVE");
verify(getRequestedFor(urlPathMatching("/api/users.*")));
}
}
/**
* PRODUCER TESTS - Generated from Contracts
*/
@SpringBootTest
public static class UserControllerProducerTest {
@Autowired
private WebTestClient webTestClient;
@MockBean
private UserService userService;
@Test
public void shouldReturnUserWhenExists() {
// Given
User user = new User(1L, "John Doe", "[email protected]", "ACTIVE");
user.setCreatedAt(Date.from(Instant.parse("2024-01-15T10:30:00.000Z")));
when(userService.findById(1L)).thenReturn(user);
// When & Then
webTestClient.get().uri("/api/users/1")
.exchange()
.expectStatus().isOk()
.expectHeader().contentType(MediaType.APPLICATION_JSON)
.expectBody()
.jsonPath("$.id").isEqualTo(1)
.jsonPath("$.name").isEqualTo("John Doe")
.jsonPath("$.email").isEqualTo("[email protected]")
.jsonPath("$.status").isEqualTo("ACTIVE")
.jsonPath("$.createdAt").isEqualTo("2024-01-15T10:30:00.000Z");
}
@Test
public void shouldReturnNotFoundWhenUserDoesNotExist() {
// Given
when(userService.findById(999L)).thenReturn(null);
// When & Then
webTestClient.get().uri("/api/users/999")
.exchange()
.expectStatus().isNotFound();
}
@Test
public void shouldCreateUserWhenValid() {
// Given
User newUser = new User(null, "Jane Smith", "[email protected]", null);
User createdUser = new User(2L, "Jane Smith", "[email protected]", "ACTIVE");
createdUser.setCreatedAt(Date.from(Instant.parse("2024-01-15T10:30:00.000Z")));
when(userService.create(any(User.class))).thenReturn(createdUser);
// When & Then
webTestClient.post().uri("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue("""
{
"name": "Jane Smith",
"email": "[email protected]"
}
""")
.exchange()
.expectStatus().isCreated()
.expectHeader().contentType(MediaType.APPLICATION_JSON)
.expectBody()
.jsonPath("$.id").isEqualTo(2)
.jsonPath("$.name").isEqualTo("Jane Smith")
.jsonPath("$.email").isEqualTo("[email protected]")
.jsonPath("$.status").isEqualTo("ACTIVE")
.jsonPath("$.createdAt").isEqualTo("2024-01-15T10:30:00.000Z");
}
@Test
public void shouldReturnBadRequestWhenInvalid() {
// Given
when(userService.create(any(User.class)))
.thenThrow(new IllegalArgumentException("Name and email are required"));
// When & Then
webTestClient.post().uri("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue("""
{
"name": null,
"email": "invalid-email"
}
""")
.exchange()
.expectStatus().isBadRequest();
}
}
/**
* Configuration Classes
*/
@Configuration
@EnableWebFlux
public static class ProducerConfig {
@Bean
public UserService userService() {
return new UserService();
}
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
}
@Configuration
public static class ConsumerConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public OrderService orderService(RestTemplate restTemplate, ObjectMapper objectMapper) {
return new OrderService(restTemplate, "http://localhost:8080", objectMapper);
}
}
/**
* Contract Verification Configuration
*/
@Configuration
public static class ContractVerifierConfig {
@Bean
public ContractVerifierMessaging<?> contractVerifierMessaging() {
return new ContractVerifierMessaging<>() {
// Implementation for messaging contracts
};
}
@Bean
public ContractVerifierObjectMapper contractVerifierObjectMapper() {
return new ContractVerifierObjectMapper() {
private final ObjectMapper objectMapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
@Override
public String writeValueAsString(Object value) {
try {
return objectMapper.writeValueAsString(value);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public <T> T readValue(String value, Class<T> type) {
try {
return objectMapper.readValue(value, type);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
}
}
/**
* Maven/Gradle Configuration Examples
*/
public static class BuildConfig {
public String getMavenPluginConfig() {
return """
<!-- pom.xml -->
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>4.0.0</version>
<extensions>true</extensions>
<configuration>
<testFramework>JUNIT5</testFramework>
<baseClassForTests>com.example.BaseContractTest</baseClassForTests>
<contractsDirectory>src/main/resources/contracts</contractsDirectory>
<generatedTestSourcesDir>${project.build.directory}/generated-test-sources</generatedTestSourcesDir>
</configuration>
</plugin>
""";
}
public String getGradlePluginConfig() {
return """
// build.gradle
plugins {
id 'org.springframework.cloud.contract' version '4.0.0'
}
contractTest {
useJUnitPlatform()
testLogging {
exceptionFormat = 'full'
}
}
contractExtensions {
register("springCloudContract") {
contractsDslDir = file("src/main/resources/contracts")
generatedTestSourcesDir = file("${buildDir}/generated-test-sources")
}
}
""";
}
}
/**
* Demo and Usage Examples
*/
public static void main(String[] args) {
System.out.println("šÆ Spring Cloud Contract Demo");
System.out.println("=============================\n");
// Generate contracts
UserServiceContracts contracts = new UserServiceContracts();
System.out.println("š Generated Contracts:");
System.out.println("1. " + contracts.shouldReturnUserWhenExists().getName());
System.out.println("2. " + contracts.shouldReturnNotFoundWhenUserDoesNotExist().getName());
System.out.println("3. " + contracts.shouldCreateUserWhenValid().getName());
System.out.println("4. " + contracts.shouldReturnBadRequestWhenInvalid().getName());
System.out.println("5. " + contracts.shouldReturnPaginatedUsers().getName());
System.out.println("\nš Workflow:");
System.out.println("1. Define contracts in src/main/resources/contracts/");
System.out.println("2. Run './mvnw clean generate-test-sources'");
System.out.println("3. Generated tests appear in target/generated-test-sources/");
System.out.println("4. Implement producer to satisfy contracts");
System.out.println("5. Publish contracts to shared repository");
System.out.println("6. Consumer downloads contracts and generates stubs");
System.out.println("7. Consumer tests against stubs");
System.out.println("\nā
Benefits:");
System.out.println("- API compatibility guaranteed");
System.out.println("- Early detection of breaking changes");
System.out.println("- Clear communication between teams");
System.out.println("- Automated contract verification");
}
}
Maven Dependencies
<!-- Producer Dependencies --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-contract-verifier</artifactId> <scope>test</scope> </dependency> </dependencies> <!-- Consumer Dependencies --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-contract-stub-runner</artifactId> <scope>test</scope> </dependency> </dependencies>
Contract Files Structure
src/ āāā main/ āāā resources/ āāā contracts/ āāā getUserById.groovy āāā createUser.groovy āāā getAllUsers.groovy
Sample Contract (Groovy DSL)
package contracts
org.springframework.cloud.contract.spec.Contract.make {
request {
method 'GET'
url '/api/users/1'
}
response {
status 200
headers {
contentType(applicationJson())
}
body([
id: 1,
name: "John Doe",
email: "[email protected]",
status: "ACTIVE",
createdAt: "2024-01-15T10:30:00.000Z"
])
}
}
This Spring Cloud Contract implementation provides:
- Complete contract testing workflow for microservices
- Producer-side contract definitions with Groovy DSL
- Consumer-side stub testing with WireMock
- Automated test generation from contracts
- REST API validation for both success and error cases
- Pagination and query parameter support
- JSON schema validation with regex patterns
- Integration with Spring Boot and testing frameworks
The solution ensures API compatibility between microservices and prevents breaking changes in distributed systems.
Pyroscope Profiling in Java
Explains how to use Pyroscope for continuous profiling in Java applications, helping developers analyze CPU and memory usage patterns to improve performance and identify bottlenecks.
https://macronepal.com/blog/pyroscope-profiling-in-java/
OpenTelemetry Metrics in Java: Comprehensive Guide
Provides a complete guide to collecting and exporting metrics in Java using OpenTelemetry, including counters, histograms, gauges, and integration with monitoring tools. (MACRO NEPAL)
https://macronepal.com/blog/opentelemetry-metrics-in-java-comprehensive-guide/
OTLP Exporter in Java: Complete Guide for OpenTelemetry
Explains how to configure OTLP exporters in Java to send telemetry data such as traces, metrics, and logs to monitoring systems using HTTP or gRPC protocols. (MACRO NEPAL)
https://macronepal.com/blog/otlp-exporter-in-java-complete-guide-for-opentelemetry/
Thanos Integration in Java: Global View of Metrics
Explains how to integrate Thanos with Java monitoring systems to create a scalable global metrics view across multiple Prometheus instances.
https://macronepal.com/blog/thanos-integration-in-java-global-view-of-metrics
Time Series with InfluxDB in Java: Complete Guide (Version 2)
Explains how to manage time-series data using InfluxDB in Java applications, including storing, querying, and analyzing metrics data.
https://macronepal.com/blog/time-series-with-influxdb-in-java-complete-guide-2
Time Series with InfluxDB in Java: Complete Guide
Provides an overview of integrating InfluxDB with Java for time-series data handling, including monitoring applications and managing performance metrics.
https://macronepal.com/blog/time-series-with-influxdb-in-java-complete-guide
Implementing Prometheus Remote Write in Java (Version 2)
Explains how to configure Java applications to send metrics data to Prometheus-compatible systems using the remote write feature for scalable monitoring.
https://macronepal.com/blog/implementing-prometheus-remote-write-in-java-a-complete-guide-2
Implementing Prometheus Remote Write in Java: Complete Guide
Provides instructions for sending metrics from Java services to Prometheus servers, enabling centralized monitoring and real-time analytics.
https://macronepal.com/blog/implementing-prometheus-remote-write-in-java-a-complete-guide
Building a TileServer GL in Java: Vector and Raster Tile Server
Explains how to build a TileServer GL in Java for serving vector and raster map tiles, useful for geographic visualization and mapping applications.
https://macronepal.com/blog/building-a-tileserver-gl-in-java-vector-and-raster-tile-server
Indoor Mapping in Java
Explains how to create indoor mapping systems in Java, including navigation inside buildings, spatial data handling, and visualization techniques.