Monday, 27 October 2025

🐞 Debugging Maven Tests in IntelliJ Like a Pro

 When you’re writing tests in a Java project, sometimes a simple System.out.println() just isn’t enough. You want to step through the code, inspect variables, and understand exactly what’s going on.

If you’ve ever tried to debug your Maven tests using IntelliJ and found that your breakpoints don’t hit, this post is for you.

Let’s walk through how to properly attach a debugger to a Maven test process.

To debug your application or unit tests, you need to attach the debugger to the JVM running your tests, not the Maven build process.

Run this command instead:

mvn clean test -Dmaven.surefire.debug

You’ll see:

Listening for transport dt_socket at address: 5005

This means Maven’s Surefire Plugin (the one that runs your tests) has started a new JVM in debug mode, waiting for you to connect.

⚙️ Step 1: Set Up Remote Debug in IntelliJ

  1. Go to Run → Edit Configurations.

  2. Click + → Remote JVM Debug.

  3. Set:

    • Host: localhost

    • Port: 5005

    • Debugger mode: Attach to remote JVM

  4. Click OK to save.

🧠 Step 2: Attach and Run

Now go back to your terminal where you ran Maven. It’s currently waiting for a debugger.

In IntelliJ, click Debug ▶️ on the remote configuration you just created.

Once connected, IntelliJ will display:

Connected to the target VM, address: 'localhost:5005', transport: 'socket'

Now run your tests again if needed — and your breakpoints should hit right away 🎯

🚀 Conclusion

If your IntelliJ breakpoints weren’t working before — now you know why.
The magic lies in attaching to the Surefire (test) JVM, not the main Maven process.

Thursday, 31 July 2025

Java LTS Versions Compared: Java 8 vs 11 vs 17 vs 21

 Java has come a long way since Java 8, and with each Long-Term Support (LTS) release, the language and platform have evolved significantly. Whether you're a developer, architect, or team lead, understanding the differences between Java LTS versions can help you choose the right version for your project.

In this blog post, we'll compare the major LTS versions: Java 8, 11, 17, and 21 — highlighting their key features, improvements, and what makes each version special.


☕ Java 8 (LTS) — March 2014

Major Features:

  • ✅ Lambda Expressions (functional programming)

  • ✅ Streams API

  • ✅ Default Methods in Interfaces

  • java.time package (modern date/time API)

  • ✅ Optional<T> to reduce null checks

  • ✅ CompletableFuture for async programming

🔍 Why it matters: Java 8 was a revolution — introducing functional-style programming and new APIs that changed how Java is written.


☕ Java 11 (LTS) — September 2018

Major Features:

  • ✅ Local-variable syntax for lambdas

  • ✅ New HTTP Client (supports HTTP/2)

  • ✅ New String methods: isBlank(), lines(), repeat()

  • ✅ File I/O improvements: readString(), writeString()

  • ✅ Single-file source-code launcher: java Hello.java

  • ❌ Removed outdated modules: CORBA, Java EE

🔍 Why it matters: Java 11 brought performance gains and cleaner syntax, making it a solid upgrade target from Java 8.


☕ Java 17 (LTS) — September 2021

Major Features:

  • ✅ Sealed Classes – Control class inheritance

  • ✅ Pattern Matching for instanceof

  • ✅ Records – Concise data classes

  • ✅ Switch Expressions – More powerful and expressive

  • ✅ Text Blocks – Multiline strings with ease

  • ✅ New Random Number Generators API

🔍 Why it matters: Java 17 improves readability, reduces boilerplate, and introduces more expressive language features.


☕ Java 21 (LTS) — September 2023

Major Features:

  • ✅ Virtual Threads – Lightweight threads for high concurrency (Project Loom)

  • ✅ Pattern Matching for switch (Finalized)

  • ✅ Structured Concurrency – Simplified thread orchestration

  • ✅ Record Patterns – Pattern matching with records

  • ✅ Sequenced Collections – Ordered collection APIs

  • ✅ Scoped Values (Preview) – Better than thread-local

  • ✅ Simpler main methods with unnamed classes (Preview)

🔍 Why it matters: Java 21 is a game-changer for scalability and concurrency, especially in cloud-native and high-performance applications.

Recommendation: For new projects, use Java 21. For existing Java 8 projects, consider upgrading to at least Java 17.

💬 Have you already upgraded to Java 17 or 21? Share your experience in the comments below! 

Wednesday, 28 May 2025

Retag an existing ECR image

Sometimes you need to retag an existing AWS ECR (Elastic container registry) image to the latest in order to deploy it as the latest.

 
Use Power shell for these commands

1. Get a Specific Image from ECR by Digest


$Image = Get-ECRImageBatch -ImageId @{ imageDigest="sha256:5cf0bd5fa566c49bba44e9fab18bf340bff5f3ef224217a6f13e43321ce9" } -RepositoryName jagdev-poc/service


2. Extract the Image Manifest


$Manifest = $Image.Images[0].ImageManifest


3. Re-tag the Image with "latest"


Write-ECRImage -RepositoryName jagdev-poc/service -ImageManifest $Manifest -ImageTag latest


4. List All Images in the Repository

Get-ECRImage -RepositoryName jagdev-poc/service

Thursday, 15 June 2023

git pull error :error: remote ref is at but expected

Today I faced strange GIT error while running GIT pull command.

error: cannot lock ref 'refs/remotes/origin/Feature/Performance_Fix': is at 121133f24b3eda9c7167c7be2b0f31d282b0bbb2 but expected 58840e344e3d301761c726e4f833b83f6b261ecb

Solution : 

Run below commands to fix this issue (Update the object name stored in a ref safely, used this to delete the reference) 

git update-ref -d refs/remotes/origin/Feature/Performance_Fix

git pull


Thursday, 8 June 2023

Error : The specified type member 'Date' is not supported in LINQ to Entities

I was trying to use Date property of DateTime field in LINQ query but got this error.

Message = "The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."

Example query : 

var query = from employeeRecord in _context.EmployeeRecord 

                   where (employeeRecord.StartDate.Date== currentDate)

Solution : Use DbFunctions.TruncateTime to truncate time part from a DateTime.

Updated Query : 

var query = from employeeRecord in _context.EmployeeRecord 

                   where (DbFunctions.TruncateTime(employeeRecord.StartDate) == currentDate)

Saturday, 1 April 2023

Error while upgrading Azure function to .NET6

I was  upgrading a Function App from using version 4.0.0 of Microsoft.Azure.WebJobs.Extensions.Storage to 5.1.0 and then the app crashed on startup with the following error: 

 Error : A host error has occurred during startup operation 'dea811a2-8241-4581-a014-2f94a0aad978'. [2023-03-31T22:00:31.493Z] Microsoft.Azure.WebJobs.Extensions.ServiceBus: Could not load type 'Microsoft.Azure.WebJobs.ParameterBindingData' from assembly 'Microsoft.Azure.WebJobs, Version=3.0.34.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. 

Solution : 
  1. Downgrade to, "Microsoft.Azure.WebJobs.Extensions.Storage" version: 5.0.1 
  2. Clean the solution and run it

Thursday, 19 January 2023

InvalidOperationException: Can't use schemaId for type The same schemaId is already used for type

 After adding new bean to project I got below error during startup


13:44:19:254 ---> System.InvalidOperationException: Can't use schemaId "$Employee" for type "$staff.Employee". The same schemaId is already used for type "$test.Employee" 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository.RegisterType(Type type, String schemaId) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator.GenerateReferencedSchema(DataContract dataContract, SchemaRepository schemaRepository, Func`1 definitionFactory) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator.GenerateConcreteSchema(DataContract dataContract, SchemaRepository schemaRepository) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator.GenerateSchemaForType(Type modelType, SchemaRepository schemaRepository) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator.GenerateSchema(Type modelType, SchemaRepository schemaRepository, MemberInfo memberInfo, ParameterInfo parameterInfo) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator.CreateArraySchema(DataContract dataContract, SchemaRepository schemaRepository) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator.<>c__DisplayClass10_0.b__1() 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator.GenerateConcreteSchema(DataContract dataContract, SchemaRepository schemaRepository) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator.GenerateSchemaForParameter(Type modelType, SchemaRepository schemaRepository, ParameterInfo parameterInfo) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator.GenerateSchema(Type modelType, SchemaRepository schemaRepository, MemberInfo memberInfo, ParameterInfo parameterInfo) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateSchema(Type type, SchemaRepository schemaRepository, PropertyInfo propertyInfo, ParameterInfo parameterInfo) 13:44:19:254 --- End of inner exception stack trace --- 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateSchema(Type type, SchemaRepository schemaRepository, PropertyInfo propertyInfo, ParameterInfo parameterInfo) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateRequestBodyFromBodyParameter(ApiDescription apiDescription, SchemaRepository schemaRepository, ApiParameterDescription bodyParameter) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateRequestBody(ApiDescription apiDescription, SchemaRepository schemaRepository) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperation(ApiDescription apiDescription, SchemaRepository schemaRepository) 13:44:19:254 --- End of inner exception stack trace --- 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperation(ApiDescription apiDescription, SchemaRepository schemaRepository) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperations(IEnumerable`1 apiDescriptions, SchemaRepository schemaRepository) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GeneratePaths(IEnumerable`1 apiDescriptions, SchemaRepository schemaRepository) 13:44:19:254 at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwagger(String documentName, String host, String basePath) 13:44:19:254 at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) 13:44:19:254 at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) 13:44:19:254 at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Solution : 

The only change needed is in your Startup.cs inside the method ConfigureServices.

You should add the following:

services.AddSwaggerGen(options =>

{

    options.CustomSchemaIds(type => type.ToString());

});

Wednesday, 7 December 2022

How do I fix dependency conflicts in npm install?

Today I was working on a front end app. I faced below error while running npm install command.


npm ERR! Conflicting peer dependency: @angular/core@6.1.10

npm ERR! node_modules/@angular/core

npm ERR!   peer @angular/core@"^6.0.3" from @angular-redux/router@9.0.0

npm ERR!   node_modules/@angular-redux/router

npm ERR!     @angular-redux/router@"^9.0.0" from the root project


Fix for Conflicting peer dependency in node.js

  • Downgrade the npm version to the previous version.
  • remove the node_modules folder.
  • remove package-lock.json.
  • please do npm install one more time to do a fresh installation of the dependency.

Saturday, 12 March 2022

Detecting a active transaction in spring application

Sometimes we need to use transactions (@Transactional) in code. We use @Transactional annotation on class and method to generate transactions.

In order to troubleshoot transaction issues, it could be helpful to verify if we have an active transaction in the current method or not.

Spring has provided a class called TransactionSychronizationManager. This class has a static method that allows us to know whether we are in a transaction (active transaction or no transaction), called isActualTransactionActive().

You can call this method and print output in logs. It will be true for active transactions false otherwise.

For example :

logger.error("Transaction is active " + TransactionSynchronizationManager.isActualTransactionActive());

Sunday, 19 December 2021

Microservices Best Practices for the Optimal Architecture Design

Microservices have fundamentally changed the way server side applications are architected. Rather than a single giant monolithic codebase hosting all the business logic of your application, microservices reflect the distributed systems model, where a group of application components work together to deliver the business needs.

1. The Single Responsibility Principle

Just like with code, where a class should have only a single reason to change, microservices should be modeled in a similar fashion. Building bloated services which are subject to change for more than one business context is a bad practice.

2. Have a separate data store(s) for your microservice

It defeats the purpose of having microservices if you are using a monolithic database that all your microservices share. Any change or downtime to that database would then impact all the microservices that use the database. Choose the right database for your microservice needs, customize the infrastructure and storage to the data that it maintains, and let it be exclusive to your microservice. Ideally, any other microservice that needs access to that data would only access it through the APIs that the microservice with write access has exposed. 


3. Use asynchronous communication to achieve loose coupling

To avoid building a mesh of tightly coupled components, consider using asynchronous communication between microservices. 

4. Fail fast by using a circuit breaker to achieve fault tolerance

If your microservice is dependent on another system to provide a response, and that system takes forever to respond, your overall response SLAs will be impacted. To avoid this scenario and quickly respond, one simple microservices best practice you can follow is to use a circuit breaker to timeout the external call and return a default response or an error. This will isolate the failing services that your service is dependent on without causing cascade failures, keeping your microservice in good health. You can choose to use popular products like Hystrix that Netflix developed.

5. Proxy your microservice requests through an API Gateway

Instead of every microservice in the system performing the functions of API authentication, request / response logging, and throttling, having an API gateway doing these for you upfront will add a lot of value. Clients calling your microservices will connect to the API Gateway instead of directly calling your service. This way you will avoid making all those additional calls from your microservice and the internal URLs of your service would be hidden, giving you the flexibility to redirect the traffic from the API Gateway to a newer version of your service. This is even more necessary when a third party is accessing your service, as you can throttle the incoming traffic and reject unauthorized requests from the API gateway before they reach your microservice. You can also choose to have a separate API gateway that accepts traffic from external networks. 

6. Ensure your API changes are backwards compatible

You can safely introduce changes to your API and release them fast as long as they don’t break existing callers. 

7. Version your microservices for breaking changes

It's not always possible to make backwards compatible changes. When you are making a breaking change, expose a new version of your endpoint while continuing to support older versions. Consumers can choose to use the new version at their convenience. However, having too many versions of your API can create a nightmare for those maintaining the code. Hence, have a disciplined approach to deprecate older versions by working with your clients or internally rerouting the traffic to the newer versions.

8. Have dedicated infrastructure hosting your microservice

You can have the best designed microservice meeting all the checks, but with a bad design of the hosting platform it would still behave poorly. Isolate your microservice infrastructure from other components to get fault isolation and best performance. It is also important to isolate the infrastructure of the components that your microservice depends on.

9. Create a separate release train

Your microservice needs to have its own separate release vehicle which is not tied to other components within your organization. This way you are not stepping on each other’s toes and wasting time coordinating with multiple teams.

10. Create Organizational Efficiencies

While microservices give you the freedom to develop and release independently, certain standards need to be followed for cross cutting concerns so that every team doesn’t spend time creating unique solutions for these. This is very important in a distributed architecture such as microservices, where you need to be able to connect all the pieces of the puzzle to see a holistic picture. Hence, enterprise solutions are necessary for API security, log aggregation, monitoring, API documentation, secrets management, config management, distributed tracing, etc. 

By following these microservices best practices, you should end up with a loosely coupled, distributed, and independent microservice system, wherein you can achieve the true benefits of a microservices architecture as listed at the beginning of this article.

Thursday, 20 May 2021

Remove a file from git pull request

Learned something amazing today.

Scenario : You have updated a file that already existed in main branch and want to remove it from the pull request.

Assume you're working on a branch (say featureBranch) off of development (means you created 
featureBranch from the development  branch) , and your pull request includes a file named AccountController.java.

To remove this file from the pull request and revert its changes, simply do :

1. Checkout your branch (featureBranch).
2. Run below command.
     git checkout development --  AccountController.java
3. Commit and push into your branch (featureBranch).

Tuesday, 23 February 2021

IntelliJ | SLF4J: Failed to load class org.slf4j.impl.StaticLoggerBinder

JAVA standalone program failed with below error on IntelliJ (Community Edition 2020.3).

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".

SLF4J: Defaulting to no-operation (NOP) logger implementation

SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

Process finished with exit code 0


Fix : 

Go to File-> Project Structure -> Modules,  then update slf4j dependency to compile. 

SLF4J


Tuesday, 26 May 2020

Java 14 Features with examples

Java 14, another non-LTS version has been released on March 17, 2020. Let's discuss it's feature with examples.

Here’s the list of Java 14 features:

  • Pattern Matching for instanceof (Preview) – JEP 305
  • Switch Expressions (Standard) – JEP 361
  • Helpful NullPointerExceptions – JEP 358
  • Records (Preview) – JEP 359
  • Text Blocks (Second Preview) – JEP 368
  • Packaging Tool (Incubator) – JEP 343
  • NUMA-Aware Memory Allocation for G1 – JEP 345
  • JFR Event Streaming – JEP 349
  • Non-Volatile Mapped Byte Buffers – JEP 352
  • ZGC on macOS – JEP 364
  • ZGC on Windows – JEP 365
  • Foreign-Memory Access API (Incubator) – JEP 370
1. Pattern Matching for instanceof (Preview) : Before Java 14, we use instanceof and cast to check the object’s type and cast to a variable. For example.

if (obj instanceof String) { // instanceof
      String str = (String) obj; // cast after type check
      if("test".equals(str)){
      }
} else {
     System.out.println("value is not a string");
}

Now using Java 14, we can refactor above code like this.if obj is an instance of String, then it is cast to String and assigned to the binding variable str.

if (obj instanceof String str) { // instanceof, cast and bind the variable
    if("test".equals(str)){
    }
} else {
    System.out.println("value is not a string");
}

2.  Switch Expressions (Standard) – JEP 361 : The switch expression was a preview feature in Java 12 and Java 13; now it is officially JDK standard feature, it means from Java 14 and onward, we can return value via switch expressions (we can use yield or label rules).

private int getSwitchValueViaYield(String mode) {
        int result = switch (mode) {
            case "Developer", "Tester":
                yield 10;
            case "Lead":
                yield 20;
            case "CTO", "CEO", "Director":
System.out.println("Supports multi line block!");
                yield 30;
            default:
                yield -1;
        };
        return result;
 }

3. Helpful NullPointerExceptions – JEP 358 : Improved the description of NullPointerExceptions by telling which variable was null. Add -XX:+ShowCodeDetailsInExceptionMessages option to enable this feature.

public class NullPointerExample {

    public static void main(String[] args) {
        String input = null;
        String result = showLowerCase(input); 
        System.out.println(result);
    }

    public static String showLowerCase(String str){
        return str.toLowerCase();
    }
}

Before JAVA 14 :

D:\Learning\JAVA 14\src>java com/blogspot/edgydebug/NullPointerExample.java
Exception in thread "main" java.lang.NullPointerException
        at com.blogspot.edgydebug.NullPointerExample.showLowerCase(NullPointerExample.java:12)

        at com.blogspot.edgydebug.NullPointerExample.main(NullPointerExample.java:7)



With JAVA 14 (-XX:+ShowCodeDetailsInExceptionMessages) :

D:\Learning\JAVA 14\src>java -XX:+ShowCodeDetailsInExceptionMessages com/blogspot/edgydebug/NullPointerExample.java
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.toLowerCase()" because "<parameter1>" is null
at com.blogspot.edgydebug.NullPointerExample.showLowerCase(NullPointerExample.java:12)
at com.blogspot.edgydebug.NullPointerExample.main(NullPointerExample.java:7)




4. Records (Preview) – JEP 359 : This feature is introduced to simplify the process of custom class creation. With a record you need to simply define a class in the following way.
Student.java :

package com.blogspot.edgydebug;
public record Student(String name, String id) {}

RecordExample.java :

package com.blogspot.edgydebug;

public class RecordExample {

     public static void main(String[] args) {
          Student student = new Student("John","12AWS34");
          System.out.println(student.name() + " "+student.id());
     }

}

D:\Learning\JAVA 14\src>javac --enable-preview --source 14 com\blogspot\edgydebug\Student.java
Note: com\blogspot\edgydebug\Student.java uses preview language features.
Note: Recompile with -Xlint:preview for details.

D:\Learning\JAVA 14\src>java --enable-preview --source 14 com\blogspot\edgydebug\RecordExample.java
Note: com\blogspot\edgydebug\RecordExample.java uses preview language features.
Note: Recompile with -Xlint:preview for details.
John 12AWS34

  • The Java compiler will generate a constructor, private final fields, accessors, equals/hashCode and toString methods automatically.
  • Points related to record class :
  • Records cannot be abstract
  • A record can neither extend a class nor it can be extended by another class. It’s a final class.
  • Records cannot extend any other class and cannot define instance fields inside the body. Instance fields must be defined in the state description only
  • The body of a record allows static fields and methods
  • Declared fields are private and final

5. Text Blocks (Second Preview) – JEP 368 : Text Blocks were introduced as a preview feature in Java 13. The text block helps easy creation of multiline string literals. It’s useful in easily creating HTML and JSON or SQL query strings.
For example :
package com.blogspot.edgydebug;
public class TextBlockExample {
      public static void main(String[] args) {
                String text = """
                                    <html>
                                   <body>\
                                   <p>Hello, '\s' World</p>\
                                  </body>
                                  </html>
                                  """;
               System.out.println(text);
   }
}


Output :
D:\Learning\JAVA 14\src>java --enable-preview --source 14 com\blogspot\edgydebug\TextBlockExample.java
Note: com\blogspot\edgydebug\TextBlockExample.java uses preview language features.
Note: Recompile with -Xlint:preview for details.
<html>
<body> <p>Hello, ' ' World</p> </body>
</html>

6. Packaging Tool (Incubator) – JEP 343 :

New jpackage tool to package a Java application into a platform-specific package.
Linux: deb and rpm
macOS: pkg and dmg
Windows: msi and exe (package the JAR file into an exe file on Windows)


7. NUMA-Aware Memory Allocation for G1 – JEP 345 : New NUMA-aware memory allocation mode, improves the G1 performance on large machines.Add +XX:+UseNUMA option to enable it.

8. JFR Event Streaming – JEP 349 : Improved the existing JFR (JDK Flight Recorder) to support event streaming, it means now we can stream the JFR events in real-time, without the need to dump the recorded events to disk and parse it manually.

9. Non-Volatile Mapped Byte Buffers – JEP 352 : Improved FileChannel API to create MappedByteBuffer that access to non-volatile memory (NVM)  a memory that can retrieve stored data even after having been power cycled. For example, this feature ensures that any changes which might still be in the cache are written back to memory.

10. ZGC on macOS – JEP 364 : Java 11 – JEP 333 introduced the Z Garbage Collector (ZGC) on Linux, and now it ports to macOS.

11. ZGC on Windows – JEP 365 : Java 11 – JEP 333 introduced the Z Garbage Collector (ZGC) on Linux, and now it ports to Windows version >= 1803.

12. Foreign-Memory Access API (Incubator) – JEP 370 : Introduce an API to allow Java programs to safely and efficiently access foreign memory outside of the Java heap.

Friday, 22 May 2020

Containerizing Angular application using Docker

Let's containerize angular application using Docker.

Pre-requisites for exercise:


  1. Install Docker for Desktop
  2. Install Node js
  3. Install Angular CLI (make sure you have the latest version of Angular CLI installed).

You must have an Angular application to containerize it. If you already have the application, then you can skip Angular Application creation step.

Create Angular Application


1. Create an folder/directory on your machine, let's say HelloWorldApp.
2. Open command-line and navigate to this directory.
3. Create Angular application using ng new HelloWorldAngular command.

Angular Application Creation



4. Navigate to created project folder cd HelloWorldAngular
5. To make sure app is running. run ng serve command here, then navigate to https://locahost:4200 in your browser.
6. Feel free to make any changes (add new components/modify existing components.

Creating Docker file


To create a docker image we must create the docker file and specify the required steps to build the image.
1. Create the Dockerfile (name of the file must be Dockerfile) without any extension in the root of your project.
2. Let's update our empty Dockerfile.

Note : Here we are going to use multistage build to create an optimized image.


Below is the detail of Dockerfile instructions.

FROM node:latest As builder

This line will tell the docker to pull the node image with tag latest if the images don't exist. We are also giving a friendly name (alias) builder to this image so we can refer it later.

WORKDIR /usr/src/app

This WORKDIR command will create the working directory in our docker image. going forward any command will be run in the context of this directory.

COPY package.json package-lock.json ./

This COPY command will copy package.json and package-lock.json from our current directory to the root of our working directory inside a container which is /usr/src/app.

RUN npm install

This RUN command will restore node_modules define in our package.json

COPY . .
This COPY command copies all the files from our current directory to the container working directory. this will copy all our source files.

RUN npm run build --prod

This command will build our angular project in production mode and create production ready files in dist/HelloWorldAngular folder.

FROM nginx:latest

This line will create a second stage nginx container where we will copy the compiled output from our build stage.

COPY --from=builder /usr/src/app/dist/HelloWorldAngular/ /usr/share/nginx/html

This is the final command of our docker file. This will copy the compiled angular app from builder stage path /usr/src/app/dist/HelloWorldAngular/ to nginx container. 

Complete Dockerfile


Complete Dockerfile

Building a docker image


Navigate to the project folder in command prompt and run the below command to build the image.


docker build . -t  jagdevsingh2020/helloworldappimage

This command will look for a docker file in the current directory and create the image. The  default convention is <DockerHubUsername>/<ImageName> e.g. jagdevsingh2020/helloworldappimage. jagdevsingh2020 is my docker hub username and helloworldappimage is the image name.
Run docker images command to verify above image. This will list all the Docker images on your machine.

Running a container


You can run the docker image using the below command.

docker run -p 4000:80 
 jagdevsingh2020/helloworldappimage

Here -p flag publishes all exposed ports to the host interfaces. we are publishing container port 80 to host 4000 port.

Navigate to your browser with http://localhost:4000 to verify your application.

Happy Learning !!

Tuesday, 28 April 2020

UnsupportedOperationException at java.util.AbstractList.add

While working on JAVA assignment, discovered strange error while trying to add an element to list. I am using example code to demonstrate and fix this exception.

Note : Here existing array is converted into list using JAVA API.

Code Sample :
    public static void main(String[] args) {     
        Integer [] array = {1,2,3};
        List<Integer> asList = Arrays.asList(array);
        asList.add(0, 100);
        asList.forEach(s-> System.out.println(s+ " "));
    }

Error : Exception in thread "main" java.lang.UnsupportedOperationException
     at java.base/java.util.AbstractList.add(AbstractList.java:153)
     at com.learning.concepts.PlusOne.main(PlusOne.java:13)

Root Cause : Arrays.asList() method returns a non-resizable list backed by the array. From that method's documentation:
Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.)
Solution : In order to use a resizable list use the following to convert array into list.

List<Integer> asList = new ArrayList<Integer>(Arrays.asList(array));

Thursday, 2 April 2020

A quick and practical example of Hexagonal Architecture in Java

1. Overview


In this tutorial, we'll discuss Hexagonal Architecture in Java through a working example.

2. Hexagonal Architecture


The core concept of this pattern is to implement the business logic inside the hexagon and expose it outside through the ports and adapters. The component that remains inside usually consists of application and domain layers, along with the core business logic. Whereas, the component for the outside world consists of layers like UI and Database or third party integrations.
In terms of programming (implementation), a port is an interface while an adapter is the concrete implementation of a given port.

3. Hexagonal Architecture example in Java


Let's create a simple Spring Boot REST App and try to register/view Student details using the Hexagonal Architecture.

3.1 Define Domain layer


To start with, we'll create an entity named Student. Then, we'll  add StudentService class to keep the core business logic to persist\view data. Here, the Student and StudentService are part of the inside component. Therefore, we'll create ports to expose them.
public class Student { 
    private int studentId; 
    private String name; 
    private int age; 
}

public interface StudentService {
    public List<Student> findAll();
    public void save(Student student);
}
Let's implement StudentService interface now.
@Service
public class StudentServiceImpl implements StudentService {
    private StudentDBPort studentDBPort;

    @Autowired
    public StudentServiceImpl(StudentDBPort studentDBPort) {
        super();
        this.studentDBPort = studentDBPort;
    }

    @Override public List<Student> findAll() {
        return studentDBPort.findAll();
    }

    @Override public void save(Student student) {
        studentDBPort.save(student);
    }
}

3.2 Declare Ports


Then, we'll create the StudentDBPort interface to communicate with the database:
public interface StudentDBPort {
    public List<Student> findAll();
    public void save(Student student);
}

3.3 Implement Adapters


Let's create the StudentControllerAdapter class that  act as a RestController. Therefore, it'll act as an adapter to REST client.
public class StudentControllerAdapter implements StudentRESTPort {
    @Autowired
    private StudentService studentService;
 
    @RequestMapping(method = RequestMethod.POST, value = "/register")
    public Student registerStudent(@RequestBody Student student) {
        studentService.save(student);
        return student;
    }
 
    @RequestMapping(method = RequestMethod.GET, value = "/viewAll")
    public List<Student> getAllStudents() {
        return studentService.findAll();
    }
}
Then, we'll create the StudentServiceDBAdapter class that implements the StudentDBPort interface. So, it'll behave as an adapter to persist data in the database:
public class StudentServiceDBAdapter implements StudentDBPort {
    private EntityManager entityManager;

    @Override
    public List<Student> findAll() {
        Session currentSession = entityManager.unwrap(Session.class);
        Query<Student> theQuery = currentSession.createQuery("from Student", Student.class);
        List<Student> students = theQuery.getResultList();
        return students;
    }

    @Override
    public void save(Student student) {
        Session currentSession = entityManager.unwrap(Session.class);
        currentSession.saveOrUpdate(student);
    }
}
That's it, we've successfully separated our App into the inside and outside components.

4. Benefits


The benefits of this architecture are:
  • Independence : The core layer is independent of outer layers
  • Testability : Each dependent (outer) component could be easily replaced with a stub implementation so that any component can be tested with ease
  • Flexibility : Any number of ports can be added easily to serve multiple functionalities\channels


5. Conclusion


In this article, we've learned how to use Hexagonal Architecture in Java. We've seen the core business logic can be exposed as ports via interfaces and consumed by different adapters through implementation classes.

Monday, 19 August 2019

Eclipse Maven Error | No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?

Faced below error while trying to maven build in Eclipse.

No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?


Solution :


  1. Eclipse -> window -> preference.
  2. Select installed JREs -> Edit
  3. Add External Jars
  4. select tools.jar from java/JDKx.x/lib folder.
  5. Click Finish

Friday, 16 August 2019

Spring Boot | Disable the Spring Banner in logs

When we start spring application below banner appears in logs.


You can remove this by using below properties in application.properties.


spring.main.banner-mode=off

Clean logs after applying this change.



Thursday, 15 August 2019

Spring Boot RESTful Web Service Complete Example

While exploring spring boot, I have decided to implement simple REST service to demonstrate GET, POST, PUT, and DELETE calls.

Prerequisite for this project :

- Eclipse with STS (Spring tool Suite) plugin
- SOAPUI
- JAVA 8
- Maven

1. Create Eclipse project.
Select File->New-> Project->Spring Starter Project
Follow the wizards and finally click on finish




2. Define Employee bean.

Monday, 29 July 2019

Common git issues and their solution

While using git, I faced some small issues and found their solution online. Here is the consolidated list.

1. Refusing to merge unrelated histories.
Command : git pull
Error : fatal: refusing to merge unrelated histories
Solution : git pull --allow-unrelated-histories

2. There is no tracking information for the current branch.
Command : git pull
Error : There is no tracking information for the current branch. Please specify which branch you want to merge with.
Solution : git branch --set-upstream-to=origin/master master

3. Not a git repository.
Command : git remote add origin https://github.com/jagdevsingh87/ATG-REST-case-study.git
Error : fatal: not a git repository (or any of the parent directories): .git
Solution : git init