In this Engineering With Java newsletter edition, we have hand-picked some interesting Java and Spring articles worth reading. Topics include OpenTelemetry tracing, Java Concurrency, Testing CORS, DTOs, Sequence Naming, Bean Injection, etc.
🚀 Grokking the Java Interview 🚀
Crack your Java interview by preparing important topics and mastering key concepts in a guided and structured way in a short time.Â
OpenTelemetry Tracing on Spring Boot: Java Agent vs. Micrometer Tracing
This article provides a detailed comparison of two methods for integrating OpenTelemetry tracing into Spring Boot applications: using the OpenTelemetry Java agent and employing Micrometer for manual instrumentation.
Java Agent Approach: The OpenTelemetry Java agent offers a straightforward setup by automatically instrumenting the application. When we deploy the agent alongside the Spring Boot application, it handles tracing without the need for code modifications. This approach is beneficial for quickly adding tracing capabilities with minimal effort, as the agent supports various libraries and frameworks out of the box.
Micrometer Approach: Micrometer is a metrics collection library that can be integrated with OpenTelemetry for more granular control over tracing. This method involves manually instrumenting application code to collect tracing data, providing greater flexibility in what is traced and how it is reported. While this approach requires additional setup and coding, it allows for a higher degree of customization and can be tailored to fit specific observability needs
In summary, the choice between the Java agent and Micrometer depends on application’s requirements. The Java agent is ideal for a quick and easy setup, whereas Micrometer provides a more customizable and controlled tracing environment.
Java Concurrency: The Happens-Before Guarantee
This article provides a comprehensive explanation of the "happens-before" relationship, a crucial concept in the Java Memory Model (JMM) that governs the ordering and visibility of operations in concurrent programming.
Happens-Before Relationship: In Java concurrency, the "happens-before" guarantee ensures that operations performed by one thread are visible to other threads in a predictable manner. If one operation happens-before another, the first operation’s effects (e.g., changes to variables) are guaranteed to be visible to the second operation.
Testing CORS in Spring Boot
explores methods for testing Cross-Origin Resource Sharing (CORS) configurations in Spring Boot applications. CORS is a security feature implemented by web browsers to control how resources are requested from different origins.
Using MockMvc: The article explains how to use
MockMvc
, a testing utility provided by Spring, to test CORS configurations. By simulating HTTP requests and examining responses, developers can verify whether the CORS headers are correctly set and whether the configuration allows or denies requests from specific origins. MockMvc provides methods to assert the presence and correctness of CORS-related headers likeAccess-Control-Allow-Origin
.Integration Tests with TestContainers: For more comprehensive testing, especially in integration tests, the article suggests using TestContainers. This approach involves spinning up a real server environment using Docker containers, allowing developers to test CORS configurations in a more realistic setting. This method helps ensure that the application's CORS settings work as expected in an actual runtime environment.
Testing CORS at the Controller Level: In addition to global CORS configurations, the article covers how to test CORS settings applied at the controller level. This involves setting CORS mappings directly on specific endpoints or controllers and ensuring these settings are honored in test scenarios.
In summary, the article provides practical guidance on testing CORS in Spring Boot applications using tools like MockMvc and TestContainers, highlighting the importance of verifying both global and controller-level CORS configurations to maintain robust security and functionality.
If you're preparing for interviews, I have some good news! I started a LinkedIn page called "Interview Prep 101," last week, where I post intriguing interview questions related to DSA, Java, Spring Boot, and SQL. If you're interested, feel free to follow the page!
Boost DTO Creation with Records & MapStruct in Spring Boot
This article explores how to enhance the creation and management of Data Transfer Objects (DTOs) in Spring Boot applications using Java records and MapStruct.
Java Records: Java records, introduced in Java 14 as a preview feature and made stable in Java 16, offer a concise way to define immutable data classes. Records are designed to hold immutable data and come with built-in methods for equality, hashing, and string representation. They simplify DTO creation by reducing boilerplate code, as they automatically generate constructors, getters, and other utility methods.
MapStruct Overview: MapStruct is a code generation library that simplifies the mapping of data between Java beans, such as converting between DTOs and entities. It generates mapping code at compile time, which reduces runtime overhead and improves performance compared to reflection-based mapping frameworks.
In summary, the article demonstrates how Java records and MapStruct can be used together to streamline the creation and mapping of DTOs in Spring Boot applications, offering a cleaner, more efficient approach to handling data.
How to Delay a Stubbed Method Response With Mockito
This article provides guidance on how to simulate delayed responses from stubbed methods using Mockito, a popular mocking framework in Java testing.
Mockito is widely used for creating mock objects and stubbing methods in unit tests. It allows developers to define the behavior of mocked objects and verify interactions, making it easier to isolate and test specific components of an application.
Simulating Delayed Responses:
Using
Answer
Interface: The article explains how to use Mockito'sAnswer
interface to introduce delays in the responses of stubbed methods. By implementing theAnswer
interface, we can define custom behavior for a method call, including adding a delay. This is done by overriding theanswer
method and usingThread.sleep()
to pause execution before returning a value. This approach allows for precise control over the delay duration and is useful for testing scenarios where timing is a factor.Example: The article provides a practical example of how to use the
Answer
interface to delay a method response. It demonstrates how to set up a mock object, stub a method to use theAnswer
interface, and introduce a delay before returning the result. This technique can help simulate slow or unresponsive services, allowing developers to test how their code handles such scenarios.Alternative Methods: While the
Answer
interface is a powerful tool for introducing delays, the article also briefly mentions alternative methods, such as usingCompletableFuture
for asynchronous delays. These alternatives might be preferable depending on the specific requirements of the test.
In summary, the article provides a practical guide for introducing delays in stubbed method responses using Mockito's Answer
interface, helping developers test how their applications handle delayed or slow service scenarios effectively.
Sequence Naming Strategies in Hibernate 6
This article explores different strategies for naming sequences in Hibernate, which is a popular ORM framework for Java. Sequences are used for generating unique primary key values in databases, and how they are named can affect database portability and maintainability.
Introduction to Sequence Naming: Hibernate supports various strategies for naming sequences, which can be configured to suit different database requirements and conventions. Naming sequences correctly is important for ensuring consistency and avoiding conflicts across different environments.
Sequence Naming Strategies:
Default Naming Strategy: By default, Hibernate uses a simple naming convention based on the entity class name or the property name. This approach may be sufficient for small projects but can lead to naming conflicts or lack of clarity in larger systems.
Implicit Naming Strategy: Hibernate provides implicit naming strategies that automatically generate sequence names based on predefined patterns. This includes using the entity name followed by a suffix or prefix. Implicit strategies help standardize naming conventions but might not always align with specific database naming policies.
Explicit Naming Strategy: For more control over sequence names, Hibernate allows developers to define explicit naming strategies. This approach involves specifying exact sequence names in the Hibernate mapping files or annotations. Explicit naming is useful for aligning with existing database schemas or adhering to specific naming conventions.
Custom Naming Strategies: Developers can also create custom naming strategies by implementing Hibernate’s
NamingStrategy
interface. Custom strategies offer the flexibility to define complex naming rules or integrate with specific organizational standards.
Understanding and selecting the right sequence naming strategy in Hibernate helps maintain a clear and consistent database schema, improving code maintainability and reducing potential conflicts.
Sending Emails in Spring Boot Using SendGrid
This article provides a guide on integrating SendGrid with a Spring Boot application to send emails. SendGrid is a cloud-based email delivery service that simplifies sending and managing transactional and marketing emails.
Configuring SendGrid in Spring Boot:
Configuration Properties: Add configuration properties to
application.properties
orapplication.yml
file to include SendGrid API key and other email settings. Define properties like the API key, sender email address, and any other necessary configurations.Email Service Class: Create a service class to handle email sending. Use the SendGrid library to construct and send email messages. The service class should handle the creation of email content, setting recipients, and invoking SendGrid’s API to send the email.
Sending Emails: Use the
SendGrid
class provided by the library to create an email object, set its properties (such as subject, sender, recipient, and body), and send it. The article provides code examples to demonstrate how to create and send an email using SendGrid in a Spring Boot application.
Error Handling: Implement error handling to manage cases where email sending fails. This includes catching exceptions and providing feedback or logging errors for troubleshooting.
Testing and Deployment: After setting up SendGrid, test email functionality to ensure emails are sent correctly. Deploy the Spring Boot application and monitor email delivery through the SendGrid dashboard.
In summary, the article provides a step-by-step guide to integrating SendGrid with Spring Boot, covering account setup, dependency management, configuration, and email sending, to enable efficient and reliable email delivery in applications.
For Loops vs. Stream.forEach: When to Use Which
This article compares traditional for
loops with the forEach
method of Java Streams, providing guidance on when to use each approach for iterating over collections.
The article suggests using for
loops when we need explicit control or when performance is a key concern. In contrast, forEach
is preferable for more readable, declarative code and when leveraging functional programming benefits.
In summary, the choice between for
loops and Stream forEach
depends on the specific requirements of the task, including performance considerations, code readability, and the need for functional programming features.
How Can We Inject Beans In Spring? 
explores various methods for injecting beans in Spring Framework applications. Bean injection is a fundamental concept in Spring that enables the framework to manage dependencies and configure application components.
Injection Methods:
Constructor Injection: This is a common and recommended method for injecting dependencies. We define the dependencies required by a bean through its constructor. Spring uses the constructor to instantiate the bean and inject the required dependencies. Constructor injection promotes immutability and ensures that all required dependencies are provided at the time of bean creation.
Setter Injection: Dependencies are injected via setter methods in the bean. This method is useful for optional dependencies or when we need to change the dependency after bean creation. Setter injection can be less preferred compared to constructor injection because it allows for partial bean initialization and might lead to mutable state.
Field Injection: Dependencies are injected directly into the fields of a bean using the
@Autowired
annotation. This approach is concise and requires less boilerplate code, but it can make the bean harder to test and less explicit in its dependencies. Field injection is generally not recommended for critical dependencies due to its potential drawbacks.Method Injection: This involves injecting dependencies into methods, typically using the
@Autowired
annotation on a method. Method injection can be used for injecting dependencies into methods that need them, but it’s less common compared to constructor and setter injection.Using
@Resource
and@Inject
Annotations: Apart from@Autowired
, Spring also supports the@Resource
(from JSR-250) and@Inject
(from JSR-330) annotations for dependency injection. These annotations provide alternative ways to specify dependencies and offer additional configuration options.
The article advises using constructor injection as the preferred method for mandatory dependencies due to its support for immutability and guaranteed initialization. Setter injection is suitable for optional dependencies, while field injection should be used cautiously due to potential testing and design issues.
Defining patterns of data transfers for Java applications with TornadoVM
This article examines how TornadoVM improves data handling and parallelism in Java applications, particularly for tasks requiring high performance and efficient data management. TornadoVM is a virtual machine designed to enhance Java applications by leveraging heterogeneous computing platforms like GPUs, FPGAs, and multi-core CPUs.
If you like this newsletter, consider liking, restacking, and sharing with others to promote this newsletter, thanks for your help!