Δευτέρα 21 Αυγούστου 2023

@ConstructorBinding in Spring Boot

                  @ConstructorBinding in Spring Boot 3



This annotation is no longer needed along with @ConfigurationProperties classes. If there's at least one constructor, Spring Boot implicitly uses constructor binding for our properties.



@ConfigurationProperties(prefix = "mail.credentials")

public class ImmutableCredentials {


    private final String authMethod;

    private final String username;

    private final String password;


    public ImmutableCredentials(String authMethod, String username, String password) {

        this.authMethod = authMethod;

        this.username = username;

        this.password = password;

    }


    public String getAuthMethod() {

        return authMethod;

    }


    public String getUsername() {

        return username;

    }


    public String getPassword() {

        return password;

    }

}


Only if we have multiple constructors, we have to use it on the prefered constructor:


@ConfigurationProperties(prefix = "mail.credentials")

public class ImmutableCredentials {


    private final String authMethod;

    private final String username;

    private final String password;

 

// constructor 1

    @ConstructorBinding

    public ImmutableCredentials(String authMethod, String username, String password) {

        this.authMethod = authMethod;

        this.username = username;

        this.password = password;

    }


// constructor 2

    public ImmutableCredentials(String authMethod, String username) {

        this.authMethod = authMethod;

        this.username = username;  

    }


    public String getAuthMethod() {

        return authMethod;

    }


    public String getUsername() {

        return username;

    }


    public String getPassword() {

        return password;

    }

}




       @ConstructorBinding was introduced in Spring Boot 2.2


Before version 2.2 one could only use setters to bind properties with Java fields. But after 2.2, this annotation was introduced to allow binding the properties via a parameterized constructor.




Sources:

Spring docs - Constructor Binding

Spring docs - ConfigurationProperties

Spring Boot 3 - Constructor Binding





Σάββατο 4 Φεβρουαρίου 2023

Project Valhalla Value objects and user-defined primitives



PROJECT VALHALLA: VALUE OBJECTS AND USER-DEFINED PRIMITIVES




THE PROBLEM

In a project there are classes that don't have any use for identity and their field values can be permanently set once on instantiation, and thus their instances don't need any synchronization and other OOP related optimizations.

However, by default they act like identity components and at runtime, the support for identity can be expensive. Particular memory location is required for object's data and extra metadata to support the object's functionalities.


PROJECT VALHALLA  

An alternative approach is to represent program data using primitive data types. As primitive values do not have a unique identity, they can be easily copied and efficiently stored as compact bit sequences. At the same time, we want to retain object-oriented semantics.

That said, the purpose here is to "augment the Java object model with value objects and user-defined primitives, combining the abstractions of OOP with the performance characteristics of primitives".



VALUE CLASSES


Value classes will be the bridge between the OOP benefits and primitives' performance.

With Valhalla, the JVM will try inlining value objects where possible. These value objects will be encoded directly   with its primitive field values, avoiding any overhead from object headers, indirections, or heap allocation.

As a non-goal of the related JEP, the Value classes will be reference types, stored in memory and can  be pointed to by multiple variables.


Structure:

   value class Shape {

     int x;

     int y;

   }

  ,where "value" dictates that the class and its fields would be Final, just like the regular VO objects.Value classes contain only primitives.


Being Final, they are immutable, and thus, lack identity:

In Java, final classes are unable to be altered after they have been created, making them immutable. This means that the values stored within their fields cannot be modified, and any attempts to do so will result in an error. This is why final classes lack identity, as their values cannot be changed, and thus their identity cannot be changed.

Subsequently we can compare Value class instances only by comparing all their field values. 


To summarize:

Value classes provide programmers with a mechanism to opt out of object identity, and in return get many of the performance benefits of primitive types, without giving up the other features of Java classes.

They cannot mutate, synchronize, and lack identity.

Value objects significantly improve object performance in many contexts, providing a good fusion of the better abstractions of objects with the better performance of primitives.


Value Classes drawbacks:

Value classes being the middle ground between objects and primitives, they present some drawbacks when used as fields or in arrays:

  • A variable of a Value type could be null, so we require additional bits to encode null.
  • As reference types, Value objects' variables must be modified atomically, so it not practical to inline Value objects.
Specifically, in an array with Value objects, there's still indirections and references to all elements that need memory usage:



This can be improved using Primitive classes, where possible:



PRIMITIVE CLASSES


A primitive class is a special kind of value class that introduces a new composite primitive type. Using class features, we can create a new primitive type containing other primitives. Primitive objects will be stored in stack as a unit, thus supporting a null-free flattened storage, and improved performance.

Contrary to Value classes, Primitive ones are more performant for arrays, as they have no references.They are stored directly in stack memory.

Structure:


Note the "primitive" keyword.

Primitive classes also have class methods to perform any calculations inside the object, ensuring encapsulation like in DDD design.

Primitive classes will come handy in the case of e.g. arrays, where their advantage over Value classes is the lack of indirections. In addition no null encoding needs exist, and atomic modification in also not needed as primitives stored in stack:

A memory layout of a Primitive array:



Primitive members are flattened memory-wise, and no extra pointers are needed.



CLASSES FOR THE BASIC PRIMITIVES


Project Valhalla is an initiative which seeks to migrate the Wrapper classes (java.lang.Integer, java.lang.Double, etc.) to become primitive classes. This is done in order to reduce the overhead of modeling primitive values with classes and offer the capabilities of class types for the basic primitives, with many details delegated to the standard library. Starting from Java 5, primitive values can be stored in the Wrapper classes and represented as objects, although there are drawbacks such as runtime costs and the potential for boxing identical values leading to two objects being unequal. JEP 401 outlines the improvements that will be made with the implementation of Project Valhalla.


ENHANCED GENERICS


To maintain the performance benefits of using primitives, existing frameworks and libraries have resorted to creating specializations such as IntStream<T> or ToIntFunction<T>. Currently, to use language primitives generically, we use boxed types, like Integer for int or Float for float, which introduces an extra layer of indirection and negates the purpose of using primitives. Enhanced generics is an effort to eliminate this workaround and allow generic types to be applied to object references, primitives, value types, and possibly even void.


SOURCES:


Official doc:

https://openjdk.org/projects/valhalla/

https://en.wikipedia.org/wiki/Project_Valhalla_(Java_language)

https://openjdk.org/jeps/8277163

https://openjdk.org/jeps/401

Παρασκευή 20 Ιανουαρίου 2023

Concurrency with Synchronized keywork and Atomic classes


 
ACHIEVING SYNCHRONIZATION
 FOR A SHARED INSTANCE BETWEEN MULTIPLE THREADS



Lets suppose we have many threads operating simultaneously on an  instance which increments a counter by 1 

But we don't want 2 or more to operate at the same time

Because this will create inconsistencies on our controlled adding - counter may increase faster and lose a value. 

So, only one thread should have access to read and write at each moment.

The next thread should get the last value and increment/write on it.

And so on.



THREADS AND MAIN MEMORY








WITH SYNCHRONIZED KEYWORD



Class/Instance for incrementing counter

public class SynchronizationWithSynchronizedKeyword {
private int counter;

int getValue() {
return counter;
}

synchronized void incrementBy1() {
counter++;
}
}

- Synchronized keyword will:

    - Stop other threads from accessing (locking)
    - Read the last value from the main memory
    - Increment it by 1
    - Write the new value in shared memory




Testing

@Test
public void test1() throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(3);
SynchronizationWithSynchronizedKeyword syncWithKeyword = new SynchronizationWithSynchronizedKeyword();

IntStream.range(0, 1000).forEach(count -> service.execute(syncWithKeyword::incrementBy1));
shutdownAndAwaitTermination(service);

assertEquals(1000, syncWithKeyword.getValue());
}
- Shared instance: syncWithKeyword
- We initiate 1000 Runnable tasks via a 3-Thread pool
- These tasks reference the shared instance's increment method
- To pass test, each task should increase the counter variable by 1, adding totally to 1000.



Helper method to gracefully shutdown the executor threads
private void shutdownAndAwaitTermination(ExecutorService pool) {
// Disable new tasks from being submitted
pool.shutdown();
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(100, TimeUnit.MILLISECONDS)) {
// Cancel currently executing tasks forcefully
pool.shutdownNow();
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(100, TimeUnit.MILLISECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ex) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
Result: Success





WITH ATOMIC VARIABLE CLASSES



Class/Instance for incrementing counter
public class SynchronizationWithAtomicClasses {
private final AtomicInteger counter = new AtomicInteger(0);

int getValue() {
return counter.get();
}

void incrementBy1() {
counter.incrementAndGet();
}
}
- AtomicInteger's incrementAndGet when called from a thread, will (atomic operation) :

    - Stop other threads from accessing (locking)
    - Read the last value from the main memory
    - Increment it by 1
    - Write the new value in shared memory



Testing

(Same as above)
@Test
public void test2() throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(3);
SynchronizationWithAtomicClasses syncWithAtomic = new SynchronizationWithAtomicClasses();

IntStream.range(0, 1000).forEach(count -> service.execute(syncWithAtomic::incrementBy1));
shutdownAndAwaitTermination(service);

assertEquals(1000, syncWithAtomic.getValue());
}
Result: Success



Τρίτη 17 Ιανουαρίου 2023

Ninja Framework (vs Spring)

 





INTRODUCTION


Ninja is a Java web framework that is lightweight and easy to use.

It is a fully-fledged framework for web development, providing amongst others:


DEPENDENCY INJECTION

ROUTING

MVC 

REST

PERSISTENCE

TESTING

METRICS

LOGGING

I18N

HOT-DEPLOYMENT




ANALYSIS /COMPARISON



DEPENDENCY INJECTION


Ninja uses Google Guice for DI, which has some benefits over the Spring Core DI:

  • Spring still relies heavily on XML configuration, meaning that type safety and refactoring are compromised. It is hard to make automated IDE refactorings on XMLs and Java files. Also, types are not checked in XML. On the other hand, Guice DI is done only on Java files.
  • While Spring DI uses String identifiers to resolve dependency implementation conflicts (when a type has many implementations), which is error-prone, Guice uses @BindingAnnotation in order to remove the need for Strings.
  • Guice allows for constructor injection, with setter injection being discouraged, Last one makes it difficult to have all dependencies centralized and under control.
  • Guice permits source code to remain framework-agnostic, and even allows for coexistence with Spring. We don't need to annotate our classes with Spring stereotypes, thus codebase can be portable.


ROUTING


Ninja has built-in mechanism to support an easy and readable routing:

public class Routes implements ApplicationRoutes {

@Override
public void init(Router router) {

router.GET().route("/index").with(ApplicationController::index);
router.GET().route("/home").with(ApplicationController::home);
router.GET().route("/hello").with(ApplicationController::hello);
router.GET().route("/editUser").with(ApplicationController::editUser);
router.GET().route("/createUser").with(ApplicationController::createUser);
router.GET().route("/books").with(ApplicationController::getAllBooks);

}
}




PERSISTENCE


By default, Ninja core provides Hibernate for persistence, including, Hibernate Validator, Hibernate EntityManager and Hibernate C3P0 for connection pool management.

We can configure DB url and credentials for a H2 along with familiar jpa setup, for example:

application.conf


persistence.xml







LIGHTWEIGHT / EASY SETUP


Using the correct maven archetype, the main skeleton and some code are generated:


Being an integrated software stack, Ninja then provides all libraries for most requirements of a web app.

As it uses convention-over-configuration, development speeds up.

A SuperDevMode functionality is provided to make the dev experience better:

Just insert above dependency and run "mvn ninja:run"



MODES AND APPLICATION CONFIG


Application configuration file is like Spring's one:

We also can reference properties within properties:



Depending on the current mode (dev, test, prod) that app runs, it can load relevant configuration:

To enable modes:

When running test cases, by default Test mode is enabled