Friday, July 2, 2021

Using MapStruct to Simplify JPA Relationship Mapping


Context

Using MapStruct with JPA (and Living with LAZY Loading)

Separating domain models from JPA entities keeps business logic clean and independent. Domain objects stay free of persistence concerns, while entities focus strictly on database structure and behavior.

To bridge both, MapStruct generates the mapping code and removes most of the boilerplate.


The Reality: LAZY Loading

Most relationships are LAZIER by default. That’s good for performance, but it affects how mapping behaves:

  • Accessing a relation during mapping may trigger queries
  • Mapping outside a transaction can fail
  • Deep mappings can introduce hidden performance issues

At that point, mapping is no longer just conversion—it depends on how data is loaded.


What Actually Works

A few practical habits make this approach reliable:

  • Load what you need first
    Don’t let mapping drive database access
  • Keep mappings focused
    Map only what the use case requires
  • Control transaction boundaries
    Map inside a transaction or ensure data is initialized
  • Handle relationships explicitly
    Especially when mapping back to entities

A Key Advantage of This Setup

Because persistence is isolated in the entity layer, you gain flexibility:

  • You can use JPA-specific optimizations freely (fetch strategies, entity graphs, custom queries)
  • You can shape entities to match database needs without polluting the domain
  • Persistence complexity stays contained in one place

This separation lets you be pragmatic on the persistence side while keeping the domain clean.


Why It’s Still Worth It

  • Clean, testable domain
  • Minimal mapping boilerplate
  • Explicit and controlled data access
  • Freedom to optimize persistence without impacting business logic

Bottom Line

LAZY loading fits well with this architecture, but it requires discipline.

The upside is control:
You decide how data is fetched, how relationships are handled, and where persistence complexity lives.

If mapping starts requiring full object graphs, it’s usually a sign to rethink the approach—projections or read models may be a better fit.



Sunday, May 23, 2021

When You Need a Pool, Not a Thread Pool: SimpleJschPool

 A simple pool SimpleJschPool with no threads

The SimpleJschPool Project

The SimpleJschPool is a custom-built solution for managing JSch SFTP sessions and channels, designed to be more lightweight and targeted than general-purpose pooling libraries like Apache Commons Pool. It's built for a specific use case where a pool of reusable, non-thread-safe objects (JSch ChannelSftp) is needed without the overhead of thread management.

The project is composed of three core components that work together to provide a streamlined pooling mechanism:

  • JschSessionProvider: This class is responsible for creating new JSch sessions. It acts as the factory for the resource being pooled. This is crucial because it encapsulates the logic for establishing a new SFTP connection, which can be a time-consuming operation.

  • TicketGenerator: This component ensures that each request receives a unique identifier, commonly referred to as a "ticket." This ticket is then used to track and retrieve a specific ChannelSftp instance from the cache, ensuring that a single channel is never accessed by multiple requests simultaneously.

  • JschChannelCache: This is the heart of the pooling logic, implemented using a Guava cache. It stores the ChannelSftp objects, mapping them to the unique tickets generated by the TicketGenerator. The cache handles the temporary storage and retrieval of the channels, making them available for reuse.

  • Semaphore:  The Semaphore is used to regulate the number of active tickets, which in turn controls the number of ChannelSftp instances allocated at any given time. This is a critical design choice, as it ensures that the non-thread-safe ChannelSftp Objects are not shared between concurrent threads. The semaphore acts as a gatekeeper, granting access to a resource only when it's available.

Why this approach?

The key design decision behind this project is to avoid the complexity of a full-fledged thread pool. Instead, it focuses on creating a simple, efficient object pool. Using aSemaphore; pool provides a way to manage resource access without needing to manage a pool of threads. This makes the solution lightweight and perfectly suited for the task of delivering reusable ChannelSftp instances without the overhead of constant session creation and teardown. It provides a simple yet robust way to handle multiple SFTP transfers concurrently in a safe manner.


Read and parse text file with just plain java

 I'll show my implementation with some print screens. I'll add it to my GitHub later. So I'll be back

ResetOnCloseStream or ReusableInputStream.

Reading an input stream multiple times is a fairly common requirement, and as far as I’ve seen, Java doesn’t provide a built-in implementation out of the box. This makes the problem interesting, especially when we want to avoid increasing the application’s memory footprint by holding multiple copies.

For example, imagine you need to process a file and also forward a copy for audit purposes. Libraries such as Apache Commons IO offer solutions using piped streams, and other approaches involve duplicating the underlying stream. However, these options usually require buffering or storing the data somewhere, which is not always practical.

A more lightweight solution is to leverage markable streams. By wrapping the original stream in a BufferedInputStream (or any stream that supports marking), we can take advantage of the following API methods:

public synchronized void mark(int readLimit) public synchronized void reset() throws IOException public boolean markSupported()
  • mark(int readLimit) records the current position in the stream.

  • Later, reset() allows us to return to that position.

  • If the stream supports marking (markSupported()), we can safely use this mechanism.

By setting the read limit to a very large value (e.g., Integer.MAX_VALUE), you can effectively “rewind” the stream back to the beginning after consumption. This idea is well discussed in the following StackOverflow thread: How to cache InputStream for multiple use.

In my case, I kept the intuitive class name from that discussion but extended it slightly:

  • Added a method to explicitly close the decorated stream.

  • Ensured that if the provided InputStream does not support marking, it is automatically wrapped in a markable one (such as BufferedInputStream).