The post Nulls Against Collectors appeared first on { 4Comprehension }.
]]>Converting a Java Stream into a List sounds trivial but can be surprising sometimes, especially when dealing with nulls and immutability.
This is one of the most basic and mocked ways of converting Streams to Lists – I’m sure you know what I’m talking about, and I’m sure you’ve done this hundreds of times already:
stream().map(...).collect(Collectors.toList());
You might ask… what’s wrong with it? And the answer is: absolutely nothing.
However, you need to accept the fact that the result List is mutable(not enforced by any contract), supports null values, and that the syntax is overly verbose:
What "functional programming" in Java feels like pic.twitter.com/4Og3OxHTu9
— Lukas Eder (@lukaseder) September 4, 2015
Luckily, in JDK10 and JDK16, we got alternatives that deal with the mentioned issues… and also brought some confusion.
Since JDK10, converting a Stream instance into an unmodifiable List is as easy as applying a dedicated Collector:
List<Integer> l = Stream.of(1).collect(Collectors.toUnmodifiableList());
However, this is not as easy as replacing every Collectors.toList() call with Collectors.toUnmodifiableList(). It turns out that the Collector returns a List that does not support null values!
And we learn it the hard way:
Stream.of(1, 2, null).collect(Collectors.toUnmodifiableList()).add(2); // java.lang.NullPointerException // at java.base/java.util.Objects.requireNonNull(Objects.java:208)
If you want to have an unmodifiable List with null values support, you need to fall back to the JDK8 unmodifiable List trick:
List<Integer> l = Stream.of(1, 2, null) .collect(Collectors.collectingAndThen( Collectors.toList(), Collections::unmodifiableList));
However, if you’re on a JDK16+, there’s a better way.
Luckily, JDK16 brought in the most convenient of all options: Stream#toList.
This is not a Collector but a convenience method callable right on a Stream instance:
List<Integer> l = Stream.of(1, 2, null).toList();
The resulting List is unmodifiable and supports null values (however, this is not explicitly enforced by the contract).
But, I would be cautious when blindly replacing Collectors.toList() and Collectors.toUnmodifiableList() with it because of two reasons:
Unfortunately, IntelliJ IDEA will suggest converting from one to the other right away, which can backfire at times:
Two new additions to Stream API provide convenient ways of converting a Stream instance into a List.
However, those should be used carefully since they are not drop-in replacements due to slightly different semantics.
The post Nulls Against Collectors appeared first on { 4Comprehension }.
]]>The post How to Stop a Java Thread Without Using Thread.stop()? appeared first on { 4Comprehension }.
]]>If you’re reading this, you’re probably wondering why, and most importantly: how do I stop a thread if I can’t just rely on the Thread#stop() method, which has been deprecated… since Java 1.2?
The quick answer is that one should use interruptions because Thread#stop is unsafe.
But if you want to understand why, how, and what is this annoying InterruptedException for… keep reading.
As much as it sounds intuitive to stop an already started thread, starting and stopping are two highly different cases. Why is that?
When we start a new thread, we’re starting from scratch, which is a clearly-defined state, but when we try to stop an existing thread, it can be in the middle of an operation that must not be terminated immediately.
Imagine a thread making changes to a thread-safe data structure. While being is in the middle of the critical section… and the thread is magically gone – locks get released, and now another thread can observe the data structure left in an inconsistent state.
Consider the following example of a thread-safe counter with some internal state:
class ThreadSafeCounter { private volatile int counter = 0; private volatile boolean dirty = false; public synchronized int incrementAndGet() { if (dirty) { throw new IllegalStateException("this should never happen"); } dirty = true; // ... Thread.sleep(5000); // boilerplate not included // ... counter = counter + 1; dirty = false; return counter; } }
As you can see, the getAndIncrement() method increments the counter and modifies the dirty flag. Locks guarantee that each time a thread enters getAndIncrement(), the dirty flag is set to false.
Now, let’s create a thread and stop it abruptly:
var threadSafeCounter = new ThreadSafeCounter(); var t1 = new Thread(() -> { while (true) { threadSafeCounter.incrementAndGet(); } }); t1.start(); Thread.sleep(500); t1.stop(); threadSafeCounter.incrementAndGet(); // Exception in thread "main" java.lang.IllegalStateException: this should never happen
Now threadSafeCounter instance, despite being correctly implemented, is permanently corrupted due to an abrupt stop of a thread.
How do we fix it?
Instead of stopping a thread, we should rely on cooperative thread interruption. In simple words, we should ask a thread to stop itself in the right moment by using Thread#interrupt.
However, calling Thread#interrupt instead of Thread#stop is not enough. A safe thread termination can be achieved only as a result of the cooperation of a caller and the thread, which means that inside a thread, we need to handle interruption signals which come in two forms:
While inside a thread, we can check if it was interrupted by calling one of the dedicated methods:
Thread.currentThread().isInterrupted(); // reads the interrupted flag Thread.interrupted(); // reads and resets the interrupted flag
There’s no universal way of handling an interruption, we need to apply an action that fits our context.
In the example from the previous section, a thread is incrementing our counter in an infinite loop. Instead of stopping immediately, we could simply wait until a thread finishes its incrementation job and then exit the loop:
var threadSafeCounter = new ThreadSafeCounter(); var t1 = new Thread(() -> { while (!Thread.interrupted()) { threadSafeCounter.incrementAndGet(); } }); t1.start(); Thread.sleep(500); t1.interrupt(); threadSafeCounter.incrementAndGet();
Now the thread exits safely in the desired moment without causing any havoc.
However, what if we try to interrupt a thread that’s currently waiting? Naturally, we can’t poll the interruption flag because a thread is preoccupied with a blocking operation.
This is why the InterruptedException exists. It’s not a standard exception, but another form of an interruption signal which exists purely for dealing with interruptions of blocking operations! Similar to Thread#interrupted, it resets the interruption flag.
Let’s modify the above example again and introduce pauses before each incrementation. Now, we need to process an InterruptedException thrown by Thread#sleep:
var threadSafeCounter = new ThreadSafeCounter(); var t1 = new Thread(() -> { while (!Thread.interrupted()) { threadSafeCounter.incrementAndGet(); try { Thread.sleep(10000); } catch (InterruptedException e) { break; } } }); t1.start(); Thread.sleep(500); t1.interrupt(); assertThat(threadSafeCounter.incrementAndGet()).isGreaterThan(0);
In our case, it was enough to just exit the loop.
However, what if you don’t feel like a particular method should be responsible for interruption handling? what if the method signature can’t be changed?
In such case, we need to restore the interruption flag and/or repackage the exception, for example:
try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); }
Source code can be found on GitHub.
The post How to Stop a Java Thread Without Using Thread.stop()? appeared first on { 4Comprehension }.
]]>The post Kotlin’s “internal” Visibility Modifier and Java Interoperability appeared first on { 4Comprehension }.
]]>Kotlin features almost excellent compatibility with Java. It’s not surprising since it was built on top of the JVM and a lot of its syntax sugar is actually implemented by using standard Java features!
For example, if we define an extension method on a standard String class, underneath it’s just a standard static method:
fun String.asHelloWorld() : String = "Hello $this" // public static final java.lang.String asHelloWorld(java.lang.String)
So… I wonder how Kotlin’s internal classes are represented in and seen from pure Java then?
Let’s see.
For those that do not know, internal modifier restricts the visibility of an element to a particular module:
internal class Foo
In the above example, the Foo class will only be accessible from a particular Maven module (or equivalents for other build tools).
This is where things become… complicated. There’s no equivalent of the internal modifier in Java language, so what happens if we compile an internal class with kotlinc and try to use it from Java?
Let’s do that and see:
// javap com.pivovarit.hello.Foo Compiled from "Hello.kt" public final class com.pivovarit.hello.Foo { public com.pivovarit.hello.Foo(); }
As you can see, Kotlin’s workaround for the sake of achieving interoperability with Java… is to treat internal classes as public ones.
This can be surprising and undesired, but understandable at the same time.
However, let’s see what happens if we enrich the class with some members:
internal class Foo { var name: String = "John" }
Compiled from "Hello.kt" public final class com.pivovarit.hello.Foo { public com.pivovarit.hello.Foo(); public final java.lang.String getName(); public final void setName(java.lang.String); }
Members seem unaffected as well. They are all public. However, the magic happens if members become internal as well:
internal class Foo { internal var name: String = "John" }
// javap com.pivovarit.hello.Foo Compiled from "Hello.kt" public final class com.pivovarit.hello.Foo { public com.pivovarit.hello.Foo(); public final java.lang.String getName$kotlin_internal(); public final void setName$kotlin_internal(java.lang.String); }
As you can see, members are still public but their names are no longer the same! They were mangled so that they are harder to call by accident from Java!
But what happens if we make members internal while leaving the class public?
class Foo { internal var name: String = "John" }
// javap com.pivovarit.hello.Foo Compiled from "Hello.kt" public final class com.pivovarit.hello.Foo { public com.pivovarit.hello.Foo(); public final java.lang.String getName$kotlin_collections(); public final void setName$kotlin_collections(java.lang.String); }
Looks like it worked as well which means that it doesn’t matter if we make the class internal or not!
Interoperability is a difficult subject if you’re trying to mix two languages with features that can be directly translated(transpiled?) from one to the other.
This all can be confusing, but it’s crucial to understand if we’re about to mix Kotlin and Java. Especially when calling Kotlin code from Java and not the other way around.
The post Kotlin’s “internal” Visibility Modifier and Java Interoperability appeared first on { 4Comprehension }.
]]>The post Java 16’s Stream#mapMulti() – a Better Stream#flatMap Replacement? appeared first on { 4Comprehension }.
]]>Nowadays, new Java versions get released so fast that small things often get unnoticed and it turns out that Java 16 brought a new interesting addition to Stream API – mapMulti() method that you probably have not heard about yet.
I bet you’re excited to look at the new method, so let’s do it then:
<R> Stream<R> mapMulti(BiConsumer<? super T, ? super Consumer<R>> mapper)
At first sight, it can seem a bit… cryptic but at its core mapMulti() is a flatMap()’s alternative. Both are used for processing Stream elements with one-to-many semantics.
However, mapMulti() gives you a chance to consume elements manually using a provided Consumer instance:
var lists = of(of(1), of(2, 3), List.<Integer>of()); var result = lists.stream() .mapMulti((list, consumer) -> list.forEach(consumer)) .collect(Collectors.toList());
And the same implemented with flatMap():
// import static java.util.List.of; var lists = of(of(1), of(2, 3), List.<Integer>of()); var result = lists.stream() .flatMap(i -> i.stream()) .collect(Collectors.toList());
if it ain’t broken, don’t fix it.
But what’s wrong with flatMap() that would justify introducing another, and less convenient method to the Stream API?
The answer is: nothing.
However, mapMulti() can be more convenient and more performant for certain edge cases(low number of elements) so you should consider the new method as a complementary addition and not a game-changer. At the end of the day, it delegates the work to flatMap() internally.
The performance gain is achieved by streamlining the construction of Stream instance that gets eventually passed to flatMap(). This is achieved by collecting resulting elements into a SpinedBuffer and then converting it into Stream:
default <R> Stream<R> mapMulti(BiConsumer<? super T, ? super Consumer<R>> mapper) { Objects.requireNonNull(mapper); return flatMap(e -> { SpinedBuffer<R> buffer = new SpinedBuffer<>(); mapper.accept(e, buffer); return StreamSupport.stream(buffer.spliterator(), false); }); }
Code snippets can be found on GitHub.
The post Java 16’s Stream#mapMulti() – a Better Stream#flatMap Replacement? appeared first on { 4Comprehension }.
]]>The post Improving Java’s Visibility Modifiers with ArchUnit appeared first on { 4Comprehension }.
]]>Encapsulation and separation of internal components from public ones is probably one of the most underrated programming techniques when it comes to achieving long-lasting maintainability.
Luckily, Java features an underrated package-private visibility modifier which helps a lot in hiding unwanted implementation details. Unfortunately, if the number of internal classes is significant, it doesn’t scale well… luckily, ArchUnit is there for us.
Separation of private from public lets you decrease coupling and gain the freedom to change implementation details without worrying about introducing unwanted breaking changes.
A real-life example would be one of my libraries – parallel-collectors. Thanks to minimizing the surface of the public API I had the chance to reorganize the internal architecture a few times without risking introducing any breaking changes at the API level.
Had I not done that, my hands would have been tied since someone could have used some of my internal classes directly.
The same applies to any other module or unit that needs to interact with something else.
Giving up on the internal package structure lets us embrace the package-private modifier and restrict the visibility of classes that should not be accessed from outside the package.
Let’s have a look at a typical package structure:
In this option, unfortunately, we need to keep all the internal classes public because package-private visibility works within one package and not the whole hierarchy.
Having said that, if we want to leverage package-private, we’d need to place them all in a single package:
Unfortunately, this approach doesn’t scale well with the number of classes.
Luckily, we can have both – internal package structure and visibility restrictions thanks to ArchUnit, which is a test library that can be used for enforcing architectural conventions.
For example, we can recreate the functionality of hierarchical package-private modifier, by restricting access to classes in sub-packages of com.pivovarit.movies, to classes residing in the whole package hierarchy:
public class ArchitectureTest { private static final JavaClasses classes = new ClassFileImporter() // ... .importPackages("com.pivovarit"); @Test void com_pivovarit_movies_shouldNotExposeInternalClasses() { classes().that().resideInAPackage("com.pivovarit.movies.*") .should() .onlyBeAccessed().byClassesThat() .resideInAPackage("com.pivovarit.movies..") .check(classes); } }
And now, if we create a class outside the package and use the public API(Rentals), tests are green:
package com.pivovarit; import com.pivovarit.movies.Rentals; public class Starter { public static void main(String[] args) { Rentals instance = Rentals.instance(); boolean rent = instance.rent(42); } }
But, if we try to access MovieDetailsRepository directly, we’ll end up with a violation:
package com.pivovarit; import com.pivovarit.movies.repository.MovieDetailsRepository; public class Starter { public static void main(String[] args) { MovieDetailsRepository movieDetailsRepository = new MovieDetailsRepository(); // java.lang.AssertionError: Architecture Violation } }
Naturally, ArchUnit can be used to enforce myriads of conventions, for example, in the project mentioned earlier, it’s used to enforce zero-dependencies policy:
@Test void shouldHaveZeroDependencies() { classes().that().resideInAPackage("com.pivovarit.collectors") .should() .onlyDependOnClassesThat() .resideInAnyPackage("com.pivovarit.collectors", "java..") // ... .check(classes); }
…or enforce the existence of a single public class:
@Test void shouldHaveSingleFacade() { classes().that().arePublic() .should().haveSimpleName("ParallelCollectors") .andShould().haveOnlyPrivateConstructors() .andShould().haveModifier(FINAL) // ... .check(classes); }
More examples can be found on the official page.
Separating internal components from public ones is one of the best things you can do to increase the maintainability of your software. Unfortunately, Java’s native tools are limited, but ArchUnit can cover cases that Java can’t.
Of course, the above examples are just a base that you can build upon. Real-life is full of edge-cases.
However, ArchUnit should help you harness the surface of your public API, but at the end of the day, it’s your job to do that. ArchUnit won’t help if you keep adding more and more exceptions to your rules.
Examples backing this article can be found on GitHub.
The post Improving Java’s Visibility Modifiers with ArchUnit appeared first on { 4Comprehension }.
]]>The post Be Careful with CompletableFuture.applyToEither and Exceptions appeared first on { 4Comprehension }.
]]>In this article, we’ll revisit the CompletableFuture.applyToEither method and try to figure out a workaround for one of its issues.
The CompletableFuture.applyToEither method is pretty self-explanatory. The idea is that you can declaratively provide a function that should be applied to a value of the first CompletableFuture that completed normally.
Imagine that we have two futures and want to print the value of whichever comes first:
CompletableFuture<Integer> f1 = CompletableFuture.completedFuture(42); CompletableFuture<Integer> f2 = new CompletableFuture<>(); f1.applyToEither(f2, i -> i).thenAccept(System.out::println).join(); // 42
Naturally, if we swap f1 with f2, we expect to witness the same result:
CompletableFuture<Integer> f1 = CompletableFuture.completedFuture(42); CompletableFuture<Integer> f2 = new CompletableFuture<>(); f2.applyToEither(f1, i -> i).thenAccept(System.out::println).join(); // 42
Which is indeed the case.
So, where’s the problem?
Unfortunately, the above breaks apart if we sprinkle some exceptions on them.
CompletableFuture<Integer> f1 = CompletableFuture.completedFuture(42); CompletableFuture<Integer> f2 = CompletableFuture.failedFuture(new NullPointerException("oh no, anyway")); f1.applyToEither(f2, i -> i).thenAccept(System.out::println).join(); // 42
So far, so good, but what happens if we swap f1 with f2 again?
CompletableFuture<Integer> f1 = CompletableFuture.completedFuture(42); CompletableFuture<Integer> f2 = CompletableFuture.failedFuture(new NullPointerException("oh no, anyway")); f2.applyToEither(f1, i -> i).thenAccept(System.out::println).join(); // Exception in thread "main" java.util.concurrent.CompletionException: java.lang.NullPointerException: oh no, anyway
It turns out that despite the fact that the other future is already completed, we never progress because the exception ends up propagating to the joint future which is not a behaviour many would expect.
Personally, I perceive it as a bug.
In order to circumvent the issue, we need to craft a new method since CompletableFuture.anyOf behaves in a similar fashion and won’t be helpful here.
To do that, we need to simply create a new CompletableFuture and introduce a race between two completions:
public static <T> CompletableFuture<T> either( CompletableFuture<T> f1, CompletableFuture<T> f2) { CompletableFuture<T> result = new CompletableFuture<>(); // ... f1.thenAccept(result::complete); f2.thenAccept(result::complete); return result; }
However, it’s not enough. What if all futures completed exceptionally? We’d be stuck with an incomplete future forever.
This can be achieved by piggybacking onto CompletableFuture.allOf:
CompletableFuture.allOf(f1, f2).whenComplete((__, throwable) -> { if (f1.isCompletedExceptionally() && f2.isCompletedExceptionally()) { result.completeExceptionally(throwable); } });
And here is the complete sample:
public static <T> CompletableFuture<T> either( CompletableFuture<T> f1, CompletableFuture<T> f2) { CompletableFuture<T> result = new CompletableFuture<>(); CompletableFuture.allOf(f1, f2).whenComplete((__, throwable) -> { if (f1.isCompletedExceptionally() && f2.isCompletedExceptionally()) { result.completeExceptionally(throwable); } }); f1.thenAccept(result::complete); f2.thenAccept(result::complete); return result; }
And in action:
CompletableFuture<Integer> f1 = CompletableFuture.completedFuture(42); CompletableFuture<Integer> f2 = CompletableFuture.failedFuture(new NullPointerException("oh no, anyway")); either(f1, f2).thenAccept(System.out::println).join(); // 42 either(f2, f1).thenAccept(System.out::println).join(); // 42
CompletableFuture.applyToEither works in a manner that’s mostly unacceptable for production and if you are looking after similar behaviour, you might need to craft a suitable utility method yourself.
All code samples can be found on GitHub along with other CompletableFuture utilities.
The post Be Careful with CompletableFuture.applyToEither and Exceptions appeared first on { 4Comprehension }.
]]>The post Integrating PIT Mutation Testing and GitHub Pages with GitHub Actions appeared first on { 4Comprehension }.
]]>PIT is a mutation testing system that allows you to spot deficiencies in your tests. You can integrate it easily with the most popular build tools. However, it would be quite convenient to have reports accessible at all times.
Let’s see how to achieve it with GitHub Pages and GitHub Actions using parallel-collectors as an example.
Integrating PIT with a Maven/Gradle project is a relatively easy job. To see all the options, visit the official page. In my case, it was enough to add the below to my pom.xml file:
<profile> <id>pitest</id> <build> <plugins> <plugin> <groupId>org.pitest</groupId> <artifactId>pitest-maven</artifactId> <version>1.5.2</version> <configuration> <excludedTestClasses> <excludedTestClass>*ArchitectureTest</excludedTestClass> </excludedTestClasses> </configuration> <dependencies> <dependency> <groupId>org.pitest</groupId> <artifactId>pitest-junit5-plugin</artifactId> <version>0.12</version> </dependency> </dependencies> </plugin> </plugins> </build> </profile>
The result of each run is a handy HTML report:
And now, once we enable GitHub Pages for our repository:
We can craft a custom GitHub Actions workflow that:
We can run PIT by building a simple pipeline:
name: pitest on: push: branches: - master paths-ignore: - '**.md' - '**.yml' - '**.yaml' jobs: build: runs-on: ubuntu-latest strategy: matrix: java: [ '8' ] architecture: [ 'x64' ] name: Mutation Testing with JDK ${{ matrix.java }} on ${{ matrix.architecture }} steps: - uses: actions/checkout@v2.3.4 - name: Setup JDK uses: actions/setup-java@v1 with: java-version: ${{ matrix.java }} architecture: ${{ matrix.architecture }} - uses: actions/cache@v2 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-maven- - name: Run Mutation Testing run: mvn package -Ppitest org.pitest:pitest-maven:mutationCoverage
The second part can be achieved by using a dedicated GitHub Actions extension:
- name: Deploy uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./target/pit-reports/*/
And now, whenever a new change is published to the master branch, the PIT report will be published to the GitHub Pages site/branch associated with a given repository.
In our case, the result is accessible here.
…and it already helped me spot quite a serious testing deficiency, so it was a time well spent.
PIT helped me spot an interesting testing deficiency in https://t.co/Rv3Tc1vOrLhttps://t.co/hGDmY75CMW
CC @_pitest pic.twitter.com/bU5D3LBggW
— Grzegorz Piwowarek (@pivovarit) November 17, 2020
The pipeline and pom.xml file can be found on GitHub, PIT results can be browsed here.
The post Integrating PIT Mutation Testing and GitHub Pages with GitHub Actions appeared first on { 4Comprehension }.
]]>The post GitHub Actions, reveal.js, and Automating the PDF Conversion appeared first on { 4Comprehension }.
]]>I’ve been using reveal.js as my main Slides as Code framework for a while. However, creating PDFs manually by “printing” a webpage into a PDF file was never fun(especially when conference staff is pushing you to quickly copy the slides to their USB stick) so I needed to figure out a better way.
DeckTape is a convenient PDF exporter for various HTML presentation frameworks that provides a command-line utility that accepts HTML files and spits out a PDF file. Splendid! We’re already one step ahead!
However, I found myself often presenting from various devices and some of them were not for me to configure, so I decided to automate PDF creation fully by setting up a GitHub Actions workflow.
It turns out that DeckTape is conveniently encapsulated in a Docker container, which makes the setup trivial.
Essentially, it’s enough to run the following line to land a successful conversion:
docker run --rm -t -v `pwd`:/slides -v ~:/home/user astefanutti/decktape /home/user/slides.html slides.pdf
Let’s automate it.
GitHub Actions is GitHub’s native CI tool which we could use for building our automation.
What we want to do is to run a simple workflow after a change is made to the master branch:
As we’ve seen above, it should be relatively easy to generate a PDF:
- name: Create "/slides" directory run: mkdir slides && sudo chmod 777 slides - name: Build PDF run: docker run --rm -t -v `pwd`:/slides -v ~:/home/user astefanutti/decktape reveal-js-presentation/index.html slides/reveal-js-presentation.pdf
We already know how to create a PDF. Now we need to figure out how to deploy files to another branch.
That sounds like a job for the peaceiris/actions-gh-pages GitHub Actions plugin. There are other plugins that could do the same job, but this one seems the easiest to use for our use case:
- name: Deploy uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./slides publish_branch: slides keep_files: true
Let’s run it.
And here we are. The workflow executes and we end up with a freshly-generated PDF file residing in the desired branch:
Below you can find a complete Github Actions workflow and the presentation itself.
name: reveal-pdf on: push: branches: - master paths: - 'reveal-js-presentation/*' jobs: build: runs-on: ubuntu-latest name: Generate PDF steps: - uses: actions/checkout@v2.3.4 - name: Create "/slides" directory run: mkdir slides && sudo chmod 777 slides - name: Build PDF run: docker run --rm -t -v `pwd`:/slides -v ~:/home/user astefanutti/decktape reveal-js-presentation/index.html slides/reveal-js-presentation.pdf - name: Deploy uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./slides publish_branch: slides keep_files: true
The post GitHub Actions, reveal.js, and Automating the PDF Conversion appeared first on { 4Comprehension }.
]]>The post Spring’s Lightweight JPA/Hibernate Alternatives appeared first on { 4Comprehension }.
]]>Hibernate is a fantastic piece of engineering which became pretty much a default persistence solution for Java projects around the world.
However, many admit that it’s often a bit too feature-rich and that things like lazy-loading, dirty-checking, schema generation, session management, etc., make it unnecessarily heavy, unpredictable, and hard to debug.
Luckily, Spring ecosystem features two interesting alternatives that many are not aware of.
These are:
Let’s have a brief look at them.
Remember JDBC(Java Database Connectivity)?
Most of us remember it for its inconvenient/old-school API:
try (Connection conn = DriverManager.getConnection(DB_URL, "user", "pass"); Statement stmt = conn.createStatement()) { try (ResultSet rs = stmt.executeQuery("SELECT id, name, surname, age FROM Users")) { while (rs.next()) { int id = rs.getInt("id"); int age = rs.getInt("age"); String name = rs.getString("name"); String surname = rs.getString("surname"); // ... } } } catch (Exception se) { throw new RuntimeException(se); }
Not even mentioning working with prepared statements, batching, and transaction support.
Luckily, Spring JDBC provides a tool that makes it straightforward to work with JDBC – the mighty JdbcTemplate:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
You can think of it as a generic database client that allows you to write and execute SQL statements… and that’s all. No magic, dirty-checking, lazy-initialization, object-relational mapping. Just you and SQL.
Imagine we want to persist a simple Movie class(technically, we don’t even need a class to persist, we can persist arbitrary data):
public class Movie { private long id; private String title; // boilerplate removed }
To do that, we need to write our custom repository that exposes CRUD operations and internally uses JdbcTemplate:
public interface MovieRepository { Optional<Movie> findOneById(long id); void save(Movie movie); }
And the implementation injecting JdbcTemplate:
@Repository class JdbcMovieRepository implements MovieRepository { private final JdbcTemplate jdbcTemplate; public JdbcMovieRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } // ... }
And now, if we want to save a Movie instance into a database, we need to write our SQL by hand and pass to JdbcTemplate#update method along with values that need to be inserted:
jdbcTemplate.update( "INSERT INTO MOVIES(id, title) VALUES(?, ?)", movie.getId(), movie.getTitle());
And that’s all.
Queries are equally straightforward:
jdbcTemplate.queryForObject( "SELECT * FROM MOVIES WHERE id = ?", (rs, rowId) -> new Movie(rs.getLong("id"), rs.getString("title")), id);
Notice that this is everything that you need to worry about. No more SQL debugging, lazy-loading, dirty-checking, proxies and surprises like:
I just 'fixed' N+1 problem in #Hibernate. Inheritance model was so complex it reminded me of the Forrester family from The Bold and the Beautiful. So I wrote 10 lines of elegant HQL. It turned into 400-lines long SQL query. 17 JOINS, 291 columns. It's 10x slower. How's your day?
— Tomasz Nurkiewicz (@tnurkiewicz) August 6, 2020
Unfortunately, we need to write boilerplate mapping code by ourselves, but it’s a tiny inconvenience for the delayed gratification of working with predictable software.
However, if you do really miss entity mapping, make sure to check the next section.
You can find a complete code sample on GitHub.
Spring Data JDBC is a skimmed version of Spring Data JPA (an abstraction over Hibernate’s EntityManager). It looks and feels like Spring Data JPA, but without excessive “magic”.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency>
All your classic JPA-like annotations are there:
import org.springframework.data.annotation.Id; import org.springframework.data.relational.core.mapping.Table; @Table("movies") public class Movie { @Id private long id; private String title; // boilerplate removed }
Now it’s possible to implement custom repositories using the standard Spring Data way:
@Repository public interface MovieRepository extends CrudRepository<Movie, Long> { }
And we’re ready to perform CRUD operations on our entity without writing any mapping code, and dealing with lazy-loading and dirty-checking:
private final MovieRepository movieRepository; // ... movieRepository.findById(42L).ifPresent(System.out::println);
However, it’s worth remembering that Spring Data JDBC doesn’t provide automatic schema generation and Spring Data’s signature derived queries.
So if we want to expose custom methods, we need to resort to @Query annotations on top of repository interface methods:
@Repository public interface MovieRepository extends CrudRepository<Movie, Long> { @Query("SELECT * FROM movies WHERE title=:title") List<Movie> findByTitle(@Param("title") String title); }
Besides Spring Data repository interfaces, we get access to a variation over JdbcTemplate called JdbcAggregateTemplate, which exposes JdbcTemplate-like methods but without direct SQL manipulation:
private final JdbcAggregateTemplate jdbcAggregateTemplate; // ... jdbcAggregateTemplate.insert( new Movie(42, "The Hitchhiker's Guide to the Galaxy"));
Definitely worth researching if you don’t rely on Hibernate’s full potential.
You can find a complete code sample on GitHub.
As you can see, if you don’t rely on Hibernate’s advanced features, Spring provides handy lightweight alternatives that can simplify your projects.
Personally, I’d rather choose raw JdbcTemplate over Spring Data JDBC since the latter has a steeper learning curve and some unusual edge cases which can be confusing for people that got used to Hibernate. At the same time, I don’t mind paying the price of writing my entity mapping code.
If you want to have a look outside the Spring ecosystem, you can have a look at:
And keep an eye out for the JdbcTemplate’s reactive brother:
JdbcTemplate has been the central component for synchronous relational database access, @springframework 5.3 introduces DatabaseClient for reactive database access (based on #R2DBC)#springone pic.twitter.com/3xWkoNhoXX
— Sergi Almar (@sergialmar) September 2, 2020
Both code samples are available on GitHub. Feel free to play around with them.
The post Spring’s Lightweight JPA/Hibernate Alternatives appeared first on { 4Comprehension }.
]]>The post Explaining Event Sourcing with Data Structures (1/3) appeared first on { 4Comprehension }.
]]>In this series, we’ll revisit the concept of event sourcing by implementing a PoC of a hypothetical data structure – an event-sourced list, and then improve it further in subsequent articles by making it concurrent and memory-friendly.
Over the years, we got used to the fact that most business applications persist state in some external storage which often generates extra work when it comes to ensuring auditability or reconstructing past states. But what if we dropped the assumption that we need to store the state?
For example, imagine storing users’ account balances. That’s as easy as a single database entry:
Event-sourcing is a concept in which, instead of the state, we store state-changing events, and derive the actual state only when needed.
This opens up a lot of possibilities when it comes to auditability and deriving new information!
With event-sourcing, you get access to the whole operation history and not just a raw number. You can trace all past events, past states, that led to that particular value that represents the current state.
Marvelous!
Once we know that, let’s see if we can apply this idea to a common list.
Let’s start by defining the canvas for our implementation:
public class ESList<T> implements List<T> { ... }
Just like we established above, in order to implement an event-sourced data structure, we’d need to store state-changing events/operations and not the state itself, and then run our methods against the state recreated on the spot.
In order to achieve this, we need to:
The internal event log is the core of our implementation. This is the history of all modifications applied to the data structure and can be represented as a simple list:
private final List<ListOp<T>> opLog = new ArrayList<>();
An operation is effectively just a function that takes some list and returns the result of such operation:
interface ListOp<R> { Object apply(List<R> list); }
So, an operation representing the addition could be implemented as:
class AddOp<T> implements ListOp<T> { private final T elem; AddOp(T elem) { this.elem = elem; } @Override public Object apply(List<T> list) { return list.add(elem); } @Override public String toString() { return String.format("add(element = %s)", elem); } }
Now, whenever we implement any state-changing method, we simply need to create a representation of the operation, store it, and apply to a recreated state so that we can return the result of the operation:
@Override public boolean add(T t) { return (boolean) handle(new AddOp<>(t)); }
Now, if we wanted to recreate the state of the list at any point in time, we’d need to rerun all the operations since the beginning of time.
Better be safe than sorry so it’s better to return a result wrapped in an Optional instance:
public Optional<List<T>> snapshot(int version) { if (version > opLog.size()) { return Optional.empty(); } var snapshot = new ArrayList<T>(); for (int i = 0; i <= version; i++) { try { opLog.get(i).apply(snapshot); } catch (Exception ignored) { } } return Optional.of(snapshot); } public List<T> snapshot() { return snapshot(opLog.size()) .orElseThrow(IllegalStateException::new); }
The empty catch block might look controversial, but it’s crucial when it comes to tracing failures. We’ll add some logging later on.
And now we can finalize the event handling logic. Notice that we need to first recreate the current state before adding the operation to the log:
private Object handle(ListOp<T> op) { List<T> snapshot = snapshot(); opLog.add(op); return op.apply(snapshot); }
And now, all query methods of List interface will need to recreate the state first:
@Override public int indexOf(Object o) { return snapshot().indexOf(o); } @Override public int lastIndexOf(Object o) { return snapshot().lastIndexOf(o); } @Override public ListIterator<T> listIterator() { return snapshot().listIterator(); } // ...
Would be also handy to have a method informing us how many versions of the data structure exists:
public int version() { return opLog.size(); }
Additionally, to make it convenient for us to observe changes, let’s add one extra method to display the history of all operations:
public void displayLog() { for (int i = 0; i < opLog.size(); i++) { System.out.printf("v%d :: %s%n", i, opLog.get(i).toString()); } }
And now, let’s see it in action by performing some modifications and eventually clearing the list:
public static void main(String[] args) { ESList<Integer> objects = ESList.newInstance(); objects.add(1); objects.add(2); objects.add(3); objects.addAll(List.of(4, 5)); objects.remove(Integer.valueOf(1)); objects.clear(); objects.displayLog(); System.out.println(); for (int i = 0; i < objects.version(); i++) { System.out.println("v" + i + " :" + objects.snapshot(i).get()); } }
Despite the fact that by clearing the list we got back to square one, we can see that the whole history is maintained and we managed to recreate all existing versions of the data structure:
v0 :: init[] v1 :: add(element = 1) v2 :: add(element = 2) v3 :: add(element = 3) v4 :: addAll([4, 5]) v5 :: remove(1) v6 :: clear() v0 :[] v1 :[1] v2 :[1, 2] v3 :[1, 2, 3] v4 :[1, 2, 3, 4, 5] v5 :[2, 3, 4, 5] v6 :[]
And here we are! That’s the basic idea of event-sourcing.
Naturally, this implementation has multiple downsides and is definitely nowhere near being production-ready. It’s not only not thread-safe, but an internal event log is a source of a memory leak.
Not even mentioning the fact that replaying events before each operation is dreadful inefficient but serves us well as educational material.
It might sound trivial, but event-sourcing has its downsides, so please make sure to evaluate the pros and cons before rushing with it for your next application.
Code snippets can be found over on GitHub.
In the next article, we’ll go through an exercise of making that data structure concurrent. That’s not essential to understanding the concept, but it should be pure fun anyway!
The post Explaining Event Sourcing with Data Structures (1/3) appeared first on { 4Comprehension }.
]]>