In this article, you’ll learn how to read a text file or binary (image) file in Java using various classes and utility methods provided by Java like:
BufferedReader, LineNumberReader, Files.readAllLines, Files.lines, BufferedInputStream, Files.readAllBytes, etc.
Let’s look at each of the different ways of reading a file in Java with the help of examples.
Java read file using BufferedReader
BufferedReader is a simple and performant way of reading text files in Java. It reads text from a character-input stream. It buffers characters to provide efficient reading.
Java read file line by line using Files.readAllLines()
Files.readAllLines() is a utility method of the Java NIO’s Files class that reads all the lines of a file and returns a List<String> containing each line. It internally uses BufferedReader to read the file.
Java read binary file (image file) using BufferedInputStream
All the examples presented in this article so far read textual data from a character-input stream. If you’re reading a binary data such as an image file then you need to use a byte-input stream.
BufferedInputStream lets you read raw stream of bytes. It also buffers the input for improving performance
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
public class BufferedInputStreamImageCopyExample {
public static void main(String[] args) {
try(InputStream inputStream = Files.newInputStream(Paths.get("sample.jpg"));
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
OutputStream outputStream = Files.newOutputStream(Paths.get("sample-copy.jpg"));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) {
byte[] buffer = new byte[4096];
int numBytes;
while ((numBytes = bufferedInputStream.read(buffer)) != -1) {
bufferedOutputStream.write(buffer, 0, numBytes);
}
} catch (IOException ex) {
System.out.format("I/O error: %s%n", ex);
}
}
}
Java read file into []byte using Files.readAllBytes()
If you want to read the entire contents of a file in a byte array then you can use the Files.readAllBytes() method.
import com.sun.org.apache.xpath.internal.operations.String;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class FilesReadAllBytesExample {
public static void main(String[] args) {
try {
byte[] data = Files.readAllBytes(Paths.get("demo.txt"));
// Use byte data
} catch (IOException ex) {
System.out.format("I/O error: %s%n", ex);
}
}
}
In this article, You’ll learn how to declare variables in Kotlin, how Kotlin infers the type of variables, and what are the basic data types supported by Kotlin for creating variables.
You’ll also learn how to work with various data types and how to convert one type to another.
Variables
A variable refers to a memory location that stores some data. It has a name and an associated type. The type of a variable defines the range of values that the variable can hold, and the operations that can be done on those values.
You can declare a variable in Kotlin using var and val keywords.
A variable declared using val keyword is immutable (read-only). It cannot be reassigned after it is initialized –
val name = "Bill Gates"
name = "Satoshi Nakamoto" // Error: Val cannot be reassigned
For defining a mutable variable, i.e. a variable whose value can be changed, use the var keyword –
var country = "USA"
country = "India" // Works
Type inference
Did you notice one thing about the variable declarations in the previous section? We didn’t specify the type of variables.
Although Kotlin is a statically typed language, It doesn’t require you to explicitly specify the type of every variable you declare. It can infer the type of a variable from the initializer expression –
val greeting = "Hello, World" // type inferred as `String`
val year = 2018 // type inferred as `Int`
If you want to explicitly specify the type of a variable, you can do that like this –
// Explicitly defining the type of variables
val greeting: String = "Hello, World"
val year: Int = 2018
Note that the type declaration becomes mandatory if you’re not initializing the variable at the time of declaration –
var language // Error: The variable must either have a Type annotation or be initialized
language = "French"
The above variable declaration fails because Kotlin has no way to infer the type of the variable without an initializer expression. In this case, you must explicitly specify the type of the variable –
var language: String // Works
language = "French"
Data Types
Data Types are used to categorize a set of related values and define the operations that can be done on them.
Just like other languages, Kotlin has predefined types like Int, DoubleBoolean, Char etc.
In Kotlin, everything (even the basic types like Int and Boolean) is an object. More specifically, everything behaves like an Object.
Kotlin may represent some of the basic types like numbers, characters and booleans as primitive values at runtime to improve performance, but for the end users, all of them are objects.
This is contrary to languages like Java that has separate primitive types like int, doubleetc, and their corresponding wrapper types like Integer, Double etc.
Let’s now look at all the basic data types used in Kotlin one by one –
Numbers
Numeric types in Kotlin are similar to Java. They can be categorized into integer and floating point types.
Integers
Byte – 8 bit
Short– 16 bit
Int – 32 bit
Long – 64 bit
Floating Point Numbers
Float – 32 bit single-precision floating point value.
Double – 64 bit double-precision floating point value.
Following are few examples of numeric types –
// Kotlin Numeric Types Examples
val myByte: Byte = 10
val myShort: Short = 125
val myInt = 1000
val myLong = 1000L // The suffix 'L' is used to specify a long value
val myFloat = 126.78f // The suffix 'f' or 'F' represents a Float
val myDouble = 325.49
You can also use underscore in numeric values to make them more readable –
val hundredThousand = 100_000
val oneMillion = 1_000_000
You can declare hexadecimal and binary values like this –
val myHexa = 0x0A0F // Hexadecimal values are prefixed with '0x' or '0X'
val myBinary = 0b1010 // Binary values are prefixed with '0b' or '0B'
Note that Kotlin doesn’t have any representation for octal values.
Booleans
The type Boolean is used to represent logical values. It can have two possible values true and false.
val myBoolean = true
val anotherBoolean = false
Characters
Characters are represented using the type Char. Unlike Java, Char types cannot be treated as numbers. They are declared using single quotes like this –
val letterChar = 'A'
val digitChar = '9'
Just like other languages, special characters in Kotlin are escaped using a backslash. Some examples of escaped characters are – \n (newline), \t (tab), \r (carriage return), \b (backspace) etc.
Strings
Strings are represented using the String class. They are immutable, that means you cannot modify a String by changing some of its elements.
You can declare a String like this –
var myStr = "Hello, Kotlin"
You can access the character at a particular index in a String using str[index]. The index starts from zero –
var name = "John"
var firstCharInName = name[0] // 'J'
var lastCharInName = name[name.length - 1] // 'n'
The length property is used to get the length of a String.
Escaped String and Raw String
Strings declared in double quotes can have escaped characters like ‘\n’ (new line), ‘\t’ (tab) etc –
var myEscapedString = "Hello Reader,\nWelcome to my Blog"
In Kotlin, you also have an option to declare raw strings. These Strings have no escaping and can span multiple lines –
var myMultilineRawString = """
The Quick Brown Fox
Jumped Over a Lazy Dog.
"""
Arrays
Arrays in Kotlin are represented using the Array class. You can create an array in Kotlin either using the library function arrayOf() or using the Array() constructor.
Creating Arrays using the arrayOf library function
You can pass a bunch of values to the arrayOf function to create an array like this –
var numbers = arrayOf(1, 2, 3, 4, 5)
var animals = arrayOf("Cat", "Dog", "Lion", "Tiger")
Note that you can also pass values of mixed types to the arrayOf() function, and it will still work (but don’t do that) –
var mixedArray = arrayOf(1, true, 3, "Hello", 'A') // Works and creates an array of Objects
You can also enforce a particular type while creating the array like this –
You can access the element at a particular index in an array using array[index]. The index starts from zero –
val myDoubleArray = arrayOf(4.0, 6.9, 1.7, 12.3, 5.4)
val firstElement = myDoubleArray[0]
val lastElement = myDoubleArray[myDoubleArray.size - 1]
Every array has a size property that you can use to get the size of the array.
You can also modify the array element at an index like this –
val a = arrayOf(4, 5, 7) // [4, 5, 7]
a[1] = 10 // [4, 10, 7]
Primitive Arrays
As we learned earlier, everything in Kotlin is an object. But to improve performance it represents some of the basic types like numbers, characters and booleans as primitive types at runtime.
The arrayOf() function creates arrays of boxed/wrapper types. That is, arrayOf(1, 2, 3) corresponds to Java’s Integer[] array.
But, Kotlin provides a way to create arrays of primitive types as well. It contains specialized classes for representing array of primitive types. Those classes are – IntArray, DoubleArray, CharArray etc. You can create an array of primitive types using the corresponding library functions – intArrayOf(), doubleArrayOf(), charArrayOf() etc. –
val myCharArray = charArrayOf('K', 'O', 'T') // CharArray (corresponds to Java 'char[]')
val myIntArray = intArrayOf(1, 3, 5, 7) // IntArray (corresponds to Java 'int[]')
Creating Arrays using the Array() constructor
The Array() constructor takes two arguments –
the size of the array, and
a function that takes the array index as an argument and returns the element to be inserted at that index.
var mySquareArray = Array(5, {i -> i * i}) // [0, 1, 4, 9, 16]
The second argument to the Array() constructor is a lambda expression. Lambda expressions are anonymous functions that are declared and passed around as expressions. We’ll learn more about lambda expressions in a future tutorial.
The above lambda expression takes the index of an array element and returns the value that should be inserted at that index, which is the square of the index in this case.
Type Conversions
Unlike Java, Kotlin doesn’t support implicit conversion from smaller types to larger types. For example, Int cannot be assigned to Long or Double.
var myInt = 100
var myLong: Long = myInt // Compiler Error
However, Every number type contains helper functions that can be used to explicitly convert one type to another.
Following helper functions are supported for type conversion between numeric types –
toByte()
toShort()
toInt()
toLong()
toFLoat()
toDouble()
toChar()
Examples of explicit type conversions
Here is how you can convert an Int to Long –
val myInt = 100
val myLong = myInt.toLong() // Explicitly converting 'Int' to 'Long'
You can also convert larger types to smaller types –
val doubleValue = 176.80
val intValue = doubleValue.toInt() // 176
Every type in Kotlin, not just numeric type, supports a helper function called toString() to convert it to String.
val myInt = 1000
myInt.toString() // "1000"
You can also convert a String to a numeric type like so –
val str = "1000"
val intValue = str.toInt()
If the String-to-Number conversion is not possible then a NumberFormatException is thrown –
val str = "1000ABC"
str.toInt() // Throws java.lang.NumberFormatException
Conclusion
That’s all folks! In this article, You learned how to declare mutable and immutable variables. How type inference works in Kotlin. What are the basic data types supported in Kotlin. How to work with data types like Int, LongDouble, Char, Boolean, String and Array, and how to convert one type to another.
Heroku is a cloud platform as a service (PaaS) that you can use to deploy, manage, and scale your applications. It supports several programming languages and has a very simple and convenient deployment model.
In this article, you’ll learn how to deploy Spring Boot applications on Heroku with step by step instructions.
There are several ways of deploying spring boot apps to Heroku. I’ll take you through all of them one by one. I’ll also show you the pros and cons of using one method over the other.
Creating a Simple Spring Boot app for deployment
Before learning about deployment, Let’s first create a simple Spring Boot app that we’ll deploy on Heroku.
Bootstrapping the appThe easiest way to bootstrap a new spring boot app is using Spring Boot CLI. Just enter the following command in your terminal to generate the project using Spring Boot CLI –$ spring init -n=heroku-demo -d=web heroku-demo Using service at https://start.spring.io Project extracted to '/Users/rajeevkumarsingh/heroku-demo' The command will generate the application with all the necessary configurations in a directory named heroku-demo.You can also use the Spring Initializr web app to generate the application if you don’t want to install Spring Boot CLI:
Click Generate Project to generate and download the project.
This will downloaded a zip archive of the project with all the directories and configurations.
Building a Demo endpointLet’s add a controller endpoint to the application so that it responds with a message whenever we access the root (/) endpoint.Create a file named IndexController.java inside src/main/java/com/example/herokudemo/, and add the following code to it –package com.example.herokudemo; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class IndexController { @GetMapping("/") public String index() { return "Hello there! I'm running."; } }
Running the appYou can run the app using the following command –$ mvn spring-boot:run The app will start on port 8080 by default. You can access it by going to http://localhost:8080. You should see the message Hello there! I'm running..
Deploying a Spring Boot app on Heroku using Git and Heroku CLI
All right! Now that we have a sample app, let’s learn how to deploy it to Heroku. In this section we’ll deploy the app using Git and Heroku CLI.
You need to have a Heroku account. If you don’t have one, you can create it from Heroku’s Signup Page. Once you’re registered with Heroku, follow the steps below to deploy the Spring Boot app.
Download and install Heroku CLIHeroku CLI is a command line application that lets you create, deploy and manage Heroku apps from the command line. You can download Heroku CLI from Heroku Dev Center. You’ll also find the instructions for installing Heroku CLI on your platform on that page.
Login using your email and passwordEnter the following command to login to Heroku using Heroku CLIheroku login You will be prompted to enter your Heroku account’s email and password. Enter all the details –Enter your Heroku credentials: Email: youremail@example.com Password: ************** Logged in as youremail@example.com That’s it! You’re logged in to Heroku. We can now proceed with the deployment.
Set up Git and create a Heroku appExecute the following commands from the root directory of the project to create a local Git repository for the project –git init git add . git commit -m "initial commit" Now, create a new heroku app using heroku create command like so –$ heroku create Creating app... done, ⬢ apple-custard-73702 https://apple-custard-73702.herokuapp.com/ | https://git.heroku.com/apple-custard-73702.gitThe above command creates a new heroku app and also makes a remote repository for the app at Heroku.Heroku chooses a random unique name for the app by default. If you want to specify a custom name then you can pass the app name in the heroku create command like this –heroku create <YOUR_UNIQUE_APP_NAME> You can also rename an existing app using heroku apps:rename command –heroku apps:rename --app <OLD_NAME> <NEW_NAME> Let’s use the above command to rename our app –$ heroku apps:rename --app apple-custard-73702 projectname-heroku-demo Renaming apple-custard-73702 to projectname-heroku-demo... done Git remote heroku updated ▸ Don't forget to update git remotes for all other local checkouts of the app.
Deploy the app to HerokuFinally, you can deploy the app by simply pushing the code to the remote repository named heroku which was created by the heroku create command.git push heroku master Heroku automatically detects that the project is a Maven/Java app and triggers the build accordingly.The deployment will take some time. You should see the build logs on console. Once the application is deployed, you can open it using the following command –heroku open The app should open in the system’s default browser and you should see the message Hello there! I'm running..You can see the logs of the application anytime by running the following command –heroku logs --tail
This is the easiest method of deploying spring boot apps to Heroku. But its not the ideal option if –
Your project doesn’t use Git.
Your project is closed source and you don’t want to push the source code to Heroku.
Your project uses some dependencies that are internal to your company. In this case the source code won’t compile at Heroku because it won’t be able to download the internal dependencies.
Deploying a Spring Boot app on Heroku using Heroku CLI Deploy Plugin
Unlike the previous method, this heroku deployment method doesn’t require you to setup a Git repository for your project and push the source code to Heroku.
You can build and package the app locally and deploy the packaged jar file to Heroku. This is done using Heorku CLI Deploy Plugin. It allows you to deploy a pre-built jar or war file to Heroku.
Follow the steps below to deploy a Spring Boot app on Heroku using Heroku CLI Deploy plugin:
Install Heroku Deploy CLI PluginEnter the following command in your terminal to install the heroku-cli-deploy plugin:heroku plugins:install heroku-cli-deploy
Package your Spring Boot applicationNext, you’ll need to package the application in the form of a jar file. You can do that using mvn package command –mvn clean package This command will create a packaged jar file of the application in the target folder of the project.
Create a Heroku appNow let’s create a Heroku app using heroku create command –heroku create <APP-NAME> --no-remote Notice the use of --no-remote option. This tells heroku to not setup any git remote repository.
Deploy the jar file on HerokuFinally, you can deploy the jar file using the following command –heroku deploy:jar target/heroku-demo-0.0.1-SNAPSHOT.jar --app <APP-NAME> The above command should have deployed the app successfully. But there is a caveat here. Let’s check the logs of the application to understand that-heroku logs --tail --app <APP-NAME> If you check the logs using the above command, you’ll notice an error like this –Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 90 seconds of launch Heroku requires our application to listen on the port passed through $PORT environment variable. But the spring boot application listens on port 8080 by default.Fixing the Port binding errorThere are two ways of fixing the port binding error:
You can specify the port that the application should listen to in a property named server.port in the src/main/java/resources/application.properties file –server.port=${PORT:8080} The above property will evaluate to the PORT environment variable if it is available, otherwise it will fall back to the default port 8080.
Alternatively, you can use a Procfile to customize the command that is used to run the application. The customized command would include the server.port configuration that will be used by Spring Boot to bind the app.Create the Procfile in the root directory of the project with the following configuration –# Procfile web: java $JAVA_OPTS -jar target/heroku-demo-0.0.1-SNAPSHOT.jar -Dserver.port=$PORT $JAR_OPTS
After doing one of the above two, You can deploy the app using the same heroku deploy:jar command –heroku deploy:jar target/heroku-demo-0.0.1-SNAPSHOT.jar --app <APP-NAME> This time the application should start successfully. You can verify that by opening the app in the browser using heroku open command.
Deploying a Spring Boot app on Heroku using Heroku Maven Plugin
The Heroku Maven plugin allows you to deploy any maven application without having to install Heroku CLI. It integrates the deployment into your build system, and works out of the box with any CI / CD server like Jenkins or Travis CI.
Follow the steps below to deploy your spring boot application using Heroku Maven Plugin.
Adding and Configuring Heroku Maven Plugin Add the heroku-maven-plugin to the plugins section of your pom.xml file – Change the <appName>
You can create an app either using Heroku CLI or from the Heroku dashboard. To create the app using Heroku CLI, type the following command in your terminal –heroku create project-heroku-maven-demo Don’t forget to change the name project-heroku-maven-demo to the app name that you’ve set in the pom.xml file.If you don’t want to install Heroku CLI, then create the app from the dashboard.
Deploying the app using Heroku maven plugin
If you have Heroku CLI installed, then use the following maven command to deploy the application –mvn clean heroku:deploy If you don’t have Heroku CLI installed, then you need to set the HEROKU_API_KEY environment variable before running heroku:deploy –HEROKU_API_KEY="YOUR HEROKU API KEY" mvn clean heroku:deploy You can find the API key from Heroku dashboard.
Thanks for reading. In the next article, you’ll learn how to deploy spring boot applications on AWS using Elastic beanstalk. Also, Don’t forget to subscribe to my newsletter to get notified whenever I publish new articles on the blog.
One of the most common, and efficient, models deployed by enterprises is the Layered Architecture, also called the n-tiered pattern. It packs similar components together in a horizontal manner and is self-independent. What does that mean?
It implies that the layers of the model are interconnected to each other but not interdependent. Similar components stay at the same level allowing the layers to be separated inadvertently based on the nature of the code. It is this isolation, that lends the software layers an independent nature.
Consider an instance, wherein you’d want to switch from an Oracle database to an SQL. This shift may cause you to upend the database layer but will not have a domino effect on any other layer.
Evidently, it serves a challenge for an enterprise software architect to create layers that separate from each other. Nevertheless, since the roles of each layer are clearly distinct, it accredits this software development architecture the following qualities:
It is easily maintainable as enterprise software developers with limited, or should we say pertinent, knowledge can be assigned to operate on a single layer.
You can test changes in layers separately from each other.
Upgraded versions of the software can be implemented effortlessly.
The flow of code is top-down, meaning it enters the presentation layer first and trickles down to the bottom-most layer that is the database layer. Each layer has a designated task based on the nature of the components it preserves. These could be checking the consistency of values within the code or reformatting the code altogether.
Refactoring – a key – way to lower frontend maintenance cost is a software development process by which developers change the internal shape and size of the code. They do it without affecting its external attributes can also be carried out in an n-tiered model.
This software development architecture can be customized to add layers to the presentation, business, persistence, and database levels. Such a model is called a Hybrid Layered architecture.
Benefits
Amongst the various types of software architecture, the layered variant suits enterprises that don’t want to go overboard with experimenting and want to stick to the traditional software architecture design patterns.
Testing components become relatively easier as inter-dependencies are negligible in this format of software development engineering.
Considering many software frameworks were built with the backdrop of an n-tiered structure, applications built with them, as a result, happen to be in the layered format as well.
Potential Drawbacks
Larger applications tend to be resource-intensive if based on this format, therefore for such projects, it is advised to overlook the layered pattern.
Although the layers are independent, yet the entire version of the software is installed as a single unit. Therefore, even if you update a single layer, you would have to re-install the entire apparatus all over again.
Such systems are not scalable due to the coupling between the layers.
Ideal For
The Layered architecture pattern suits the niche of LOB i.e. Line of Business Applications. These are applications that are essential to the functioning of the business itself. For instance, the accounts department of an organization needs software such as QuickBooks, Xero, Sage or Wave Accounting for keeping financial data.
Similarly, the marketing team would demand a customer relationship management software slash tool to help them cope with the volume of interactions. In short, applications that do more than just CRUD (create, read, update, and delete) operations are suited to the layered architecture pattern.
There is something going on within the front-end community recently. Server-side rendering is getting more and more traction thanks to React and its built-in server-side hydration feature. But it’s not the only solution to deliver a fast experience to the user with a super fast time-to-first-byte (TTFB) score: Pre-rendering is also a pretty good strategy. What’s the difference between these solutions and a fully client-rendered application?
Client-rendered Application
Since frameworks like Angular, Ember.js, and Backbone exists, front-end developers have tended to render everything client-side. Thanks to Google and its ability to “read” JavaScript, it works pretty well, and it’s even SEO friendly.
With a client-side rendering solution, you redirect the request to a single HTML file and the server will deliver it without any content (or with a loading screen) until you fetch all the JavaScript and let the browser compile everything before rendering the content.
Under a good and reliable internet connection, it’s pretty fast and works well. But it can be a lot better, and it doesn’t have to be difficult to make it that way. That’s what we will see in the following sections.
Server-side Rendering (SSR)
An SSR solution is something we used to do a lot, many years ago, but tend to forget in favor of a client-side rendering solution.
With old server-side rendering solutions, you built a web page—with PHP for example—the server compiled everything, included the data, and delivered a fully populated HTML page to the client. It was fast and effective.
But… every time you navigated to another route, the server had to do the work all over again: Get the PHP file, compile it, and deliver the HTML, with all the CSS and JS delaying the page load to a few hundred ms or even whole seconds.
What if you could do the first page load with the SSR solution, and then use a framework to do dynamic routing with AJAX, fetching only the necessary data?
This is why SSR is getting more and more traction within the community because React popularized this problem with an easy-to-use solution: The RenderToString method.
This new kind of web application is called a universal app or an isomorphic app. There’s still some controversy over the exact meanings of these terms and the relationship between them, but many people use them interchangeably.
Anyway, the advantage of this solution is being able to develop an app server-side and client-side with the same code and deliver a really fast experience to the user with custom data. The disadvantage is that you need to run a server.
SSR is used to fetch data and pre-populate a page with custom content, leveraging the server’s reliable internet connection. That is, the server’s own internet connection is better than that of a user with lie-fi), so it’s able to prefetch and amalgamate data before delivering it to the user.
With the pre-populated data, using an SSR app can also fix an issue that client-rendered apps have with social sharing and the OpenGraph system. For example, if you have only one index.html file to deliver to the client, they will only have one type of metadata—most likely your homepage metadata. This won’t be contextualized when you want to share a different route, so none of your routes will be shown on other sites with their proper user content (description and preview picture) that users would want to share with the world.
Pre-rendering
The mandatory server for a universal app can be a deterrent for some and may be overkill for a small application. This is why pre-rendering can be a really nice alternative.
I discovered this solution with Preact and its own CLI that allows you to compile all pre-selected routes so you can store a fully populated HTML file to a static server. This lets you deliver a super-fast experience to the user, thanks to the Preact/React hydration function, without the need for Node.js.
The catch is, because this isn’t SSR, you don’t have user-specific data to show at this point—it’s just a static (and somewhat generic) file sent directly on the first request, as-is. So if you have user-specific data, here is where you can integrate a beautifully designed skeleton to show the user their data is coming, to avoid some frustration on their part:
There is another catch: In order for this technique to work, you still need to have a proxy or something to redirect the user to the right file.
Why?
With a single-page application, you need to redirect all requests to the root file, and then the framework redirects the user with its built-in routing system. So the first page load is always the same root file.
In order for a pre-rendering solution to work, you need to tell your proxy that some routes need specific files and not always the root index.html file.
For example, say you have four routes (/, /about, /jobs, and blog) and all of them have different layouts. You need four different HTML files to deliver the skeleton to the user that will then let React/Preact/etc. rehydrate it with data. So if you redirect all those routes to the root index.html file, the page will have an unpleasant, glitchy feel during loading, whereby the user will see the skeleton of the wrong page until it finishes loading and replaces the layout. For example, the user might see a homepage skeleton with only one column, when they had asked for a different page with a Pinterest-like gallery.
The solution is to tell your proxy that each of those four routes needs a specific file:
https://my-website.com → Redirect to the root index.html file
https://my-website.com/about → Redirect to the /about/index.html file
https://my-website.com/jobs → Redirect to the /jobs/index.html file
https://my-website.com/blog → Redirect to the /blog/index.html file
This is why this solution can be useful for small applications—you can see how painful it would be if you had a few hundred pages.
Strictly speaking, it’s not mandatory to do it this way—you could just use a static file directly. For example, https://my-website.com/about/ will work without any redirection because it will automatically search for an index.html inside its directory. But you need this proxy if you have param urls—https://my-website.com/profile/guillaume will need to redirect the request to /profile/index.html with its own layout, because profile/guillaume/index.html doesn’t exist and will trigger a 404 error.
In short, there are three basic views at play with the rendering strategies described above: A loading screen, a skeleton, and the full page once it’s finally rendered.
Depending on the strategy, sometimes we use all three of these views, and sometimes we jump straight to a fully-rendered page. Only in one use case are we forced to use a different approach:
Method
Landing (e.g. /)
Static (e.g. /about)
Fixed Dynamic (e.g. /news)
Parameterized Dynamic (e.g. /users/:user-id)
Client-rendered
Loading → Full
Loading → Full
Loading → Skeleton → Full
Loading → Skeleton → Full
Pre-rendered
Full
Full
Skeleton → Full
HTTP 404 (page not found)
Pre-rendered With Proxy
Full
Full
Skeleton → Full
Skeleton → Full
SSR
Full
Full
Full
Full
Client-only Rendering is Often Not Enough
Client-rendered applications are something we should avoid now because we can do better for the user. And doing better, in this case, is as easy as the pre-rendering solution. It’s definitely an improvement over client-only rendering and easier to implement than a fully server-side-rendered application.
An SSR/universal application can be really powerful if you have a large application with a lot of different pages. It allows your content to be focused and relevant when talking to a social crawler. This is also true for search engine robots, which now take your site’s performance into account when ranking it.
Stay tuned for a follow-up tutorial, where I will walk through the transformation of an SPA into pre-rendered and SSR versions, and compare their performance.
Logging in Spring Boot can be confusing, and the wide range of tools and frameworks make it a challenge to even know where to start. This guide talks through the most common best practices for Spring Boot logging and gives five key suggestions to add to your logging tool kit.
What’s in the Spring Boot Box?
The Spring Boot Starters all depend on spring-boot-starter-logging. This is where the majority of the logging dependencies for your application come from. The dependencies involve a facade (SLF4J) and frameworks (Logback). It’s important to know what these are and how they fit together.
SLF4J is a simple front-facing facade supported by several logging frameworks. It’s main advantage is that you can easily switch from one logging framework to another. In our case, we can easily switch our logging from Logback to Log4j, Log4j2 or JUL.
The dependencies we use will also write logs. For example, Hibernate uses SLF4J, which fits perfectly as we have that available. However, the AWS SDK for Java uses Apache Commons Logging (JCL). Spring-boot-starter-logging includes the necessary bridges to ensure those logs are delegated to our logging framework out of the box.
SLF4J usage:
At a high level, all the application code has to worry about is:
Getting an instance of an SLF4J logger (Regardless of the underlying framework): private static final Logger LOG = LoggerFactory.getLogger(MyClass.class);Copy
Writing some logs: LOG.info(“My message set at info level”);Copy
Logback or Log4j2?
Spring Boot’s default logging framework is Logback. Your application code should interface only with the SLF4J facade so that it’s easy to switch to an alternative framework if necessary.
Log4j2 is newer and claims to improve on the performance of Logback. Log4j2 also supports a wide range of appenders so it can log to files, HTTP, databases, Cassandra, Kafka, as well as supporting asynchronous loggers. If logging performance is of high importance, switching to log4j2 may improve your metrics. Otherwise, for simplicity, you may want to stick with the default Logback implementation.
This guide will provide configuration examples for both frameworks.
5 Tips for Getting the Most Out of Your Spring Boot Logging
With your initial set up out of the way, here are 5 top tips for spring boot logging.
1. Configuring Your Log Format
Spring Boot Logging provides default configurations for logback and log4j2. These specify the logging level, the appenders (where to log) and the format of the log messages.
For all but a few specific packages, the default log level is set to INFO, and by default, the only appender used is the Console Appender, so logs will be directed only to the console.
The default format for the logs using logback looks like this:
Let’s take a look at that last line of log, which was a statement created from within a controller with the message “My message set at info level”.
It looks simple, yet the default log pattern for logback seems “off” at first glance. As much as it looks like it could be, it’s not regex, it doesn’t parse email addresses, and actually, when we break it down it’s not so bad.
The variables that are available for the log format allow you to create meaningful logs, so let’s look a bit deeper at the ones in the default log pattern example.Show 102550100 entriesSearch:
Pattern Part
What it Means
%clr
%clr specifies a colour. By default, it is based on log levels, e.g, INFO is green. If you want to specify specific colours, you can do that too.
The format is: %clr(Your message){your colour}
So for example, if we wanted to add “Demo” to the start of every log message, in green, we would write: %clr(Demo){green}
%d is the current date, and the part in curly braces is the format. ${VARIABLE}:-default is a way of specifying that we should use the $VARIABLE environment variable for the format, if it is available, and if not, fall back to default. This is handy if you want to override these values in your properties files, by providing arguments, or by setting environment variables.
In this example, the default format is yyyy-MM-dd HH:mm:ss.SSS unless we specify a variable named LOG_DATEFORMAT_PATTERN. In the logs above, we can see 2020-10-19 10:09:58.152 matches the default pattern, meaning we did not specify a custom LOG_DATEFORMAT_PATTERN.
${LOG_LEVEL_PATTERN:-%5p}
Uses the LOG_LEVEL_PATTERN if it is defined, else will print the log level with right padding up to 5 characters (E.g “INFO” becomes “INFO “ but “TRACE” will not have the trailing space). This keeps the rest of the log aligned as it’ll always be 5 characters.
${PID:- }
The environment variable $PID, if it exists. If not, space.
t
The name of the thread triggering the log message.
logger
The name of the logger (up to 39 characters), in our case this is the class name.
%m
The log message.
%n
The platform-specific line separator.
%wEx
If one exists, wEx is the stack trace of any exception, formatted using Spring Boot’s ExtendedWhitespaceThrowableProxyConverter.
You can customise the ${} variables that are found in the logback-spring.xml by passing in properties or environment variables. For example, you may set logging.pattern.console to override the whole of the console log pattern.
Armed with the ability to customise your logs, you should consider adding:
Application name.
A request ID.
The endpoint being requested (E.g /health).
There are a few items in the default log that I would remove unless you have a specific use case for them:
The ‘—’ separator.
The thread name.
The process ID.
With the ability to customise these through the use of the logback-spring.xml or log4j2-spring.xml, the format of your logs is fully within your control.
2. Configuring the Destination for Your Logs (Appenders and Loggers)
An appender is just a fancy name for the part of the logging framework that sends your logs to a particular target. Both frameworks can output to console, over HTTP, to databases, or over a TCP socket, as well as to many other targets. The way we configure the destination for the logs is by adding, removing and configuring these appenders.
You have more control over which appenders you use, and the configuration of them, if you create your own custom .xml configuration. However, the default logging configuration does make use of environment properties that allow you to override some parts of it, for example, the date format.
The official docs for logback appenders and log4j2 appenders detail the parameters required for each of the appenders available, and how to configure them in your XML file. One tip for choosing the destination for your logs is to have a plan for rotating them. Writing logs to a file always feels like a great idea, until the storage used for that file runs out and brings down the whole service.
Log4j and logback both have a RollingFileAppender which handles rotating these log files based on file size, or time, and it’s exactly that which Spring Boot Logging uses if you set the logging.file property.
3. Logging as a Cross-Cutting Concern to Keep Your Code Clean (Using Filters and Aspects)
You might want to log every HTTP request your API receives. That’s a fairly normal requirement, but putting a log statement into every controller is unnecessary duplication. It’s easy to forget and make mistakes. A requirement that you want to log every method within your packages that your application calls would be even more cumbersome.
I’ve seen developers use this style of logging at trace level so that they can turn it on to see exactly what is happening in a production environment. Adding log statements to the start and end of every method is messy, and there is a better way. This is where filters and aspects save the day and avoid the code duplication.
When to Use a Filter Vs When to Use Aspect-Oriented Programming
If you are looking to create log statements related to specific requests, you should opt for using filters, as they are part of the handling chain that your application already goes through for each request. They are easier to write, easier to test and usually more performant than using aspects. If you are considering more cross-cutting concerns, for example, audit logging, or logging every method that causes an exception to be thrown, use AOP.
Using a Filter to Log Every Request
Filters can be registered with your web container by creating a class implementing javax.servlet.Filter and annotating it with @Component, or adding it as an @Bean in one of your configuration classes. When your spring-boot-starter application starts up, it will create the Filter and register it with the container.
Aspect-oriented programming enables you to fulfill cross-cutting concerns, like logging for example, in one place. You can do this without your logging code needing to sprawl across every class.
This approach is great for use cases such as:
Logging any exceptions thrown from any method within your packages (See @AfterThrowing)
Logging performance metrics by timing before/after each method is run (See @Around)
Audit logging. You can log calls to methods that have your a custom annotation on, such as adding @Audit. You only need to create a pointcut matching calls to methods with that annotation
Let’s start with a simple example – we want to log the name of every public method that we call within our package, com.example.demo. There are only a few steps to writing an Aspect that will run before every public method in a package that you specify.
Add @EnableAspectJAutoProxy to one of your configuration classes. This line tells spring-boot that you want to enable AspectJ support.
Add your pointcut, which defines a pattern that is matched against method signatures as they run. You can find more about how to construct your matching pattern in the spring boot documentation for AOP. In our example, we match any method inside the com.example.demo package.
Add your Aspect. This defines when you want to run your code in relation to the pointcut (E.g, before, after or around the methods that it matches). In this example, the @Before annotation causes the method to be executed before any methods that match the pointcut.
That’s all there is to logging every method call. The logs will appear as:
2020-10-27 19:26:33.269 INFO 2052 --- [nio-8080-exec-2]
com.example.demo.MyAspect : Called checkHealthCopy
By making changes to your pointcut, you can write logs for every method annotated with a specific annotation. For example, consider what you can do with:
@annotation(com.example.demo.Audit)Copy
4. Applying Context to Your Logs Using MDC
(This would run for every method annotated with a custom annotation, @Audit).
MDC (Mapped Diagnostic Context) is a complex-sounding name for a map of key-value pairs, associated with a single thread. Each thread has its own map. You can add keys/values to the map at runtime, and then reference the keys from that map in your logging pattern.
The approach comes with a warning that threads may be reused, and so you’ll need to make sure to clear your MDC after each request to avoid your context leaking from one request to the next.
MDC is accessible through SLF4J and supported by both Logback and Log4j2, so we don’t need to worry about the specifics of the underlying implementation.
Tracking Requests Through Your Application Using Filters and MDC
Want to be able to group logs for a specific request? The Mapped Diagnostic Context (MDC) will help.
The steps are:
Add a header to each request going to your API, for example, ‘tracking-id’. You can generate this on the fly (I suggest using a UUID) if your client cannot provide one.
Create a filter that runs once per request and stores that value in the MDC.
Update your logging pattern to reference the key in the MDC to retrieve the value.
After setting the value on your MDC, just add %X{tracking} to your logging pattern (Replacing the word “tracking” with the key you have put in MDC) and your logs will contain the value in every log message for that request.
If a client reports a problem, as long as you can get a unique tracking-id from your client, then you’ll be able to search your logs and pull up every log statement generated from that specific request.
Other use cases that you may want to put into your MDC and include on every log message include:
The application version.
Details of the request, for example, the path.
Details of the logged-in user, for example, the username.
5. Unit Testing Your Log Statements
Why Test Your Logs?
You can unit test your logging code. Too often this is overlooked because the log statements return void. For example, logger.info(“foo”); does not return a value that you can assert against.
It’s easy to make mistakes. Log statements usually involve parameters or formatted strings, and it’s easy to put log statements in the wrong place. Unit testing reassures you that your logs do what you expect and that you’re covered when refactoring to avoid any accidental modifications to your logging behaviour.
The Approach to Testing Your Logs
The Problem
SLF4J’s LoggerFactory.getLogger is static, making it difficult to mock. Searching through any outputted log files in our unit tests is error-prone (E.g we need to consider resetting the log files between each unit test). How do we assert against the logs?
The Solution
The trick is to add your own test appender to the logging framework (e.g Logback or Log4j2) that captures the logs from your application in memory, allowing us to assert against the output later. The steps are:
Before each test case, add an appender to your logger.
Within the test, call your application code that logs some output.
The logger will delegate to your test appender.
Assert that your expected logs have been received by your test appender.
Each logging framework has suitable appenders, but referencing those concrete appenders in our tests means we need to depend on the specific framework rather than SLF4J. That’s not ideal, but the alternatives of searching through logged output in files, or implementing our own SLF4J implementation is overkill, making this the pragmatic choice.
Here are a couple of tricks for unit testing using JUnit 4 rules or JUnit 5 extensions that will keep your test classes clean, and reduce the coupling with the logging framework.
Testing Log Statements Using Junit 5 Extensions in Two Steps
JUnit 5 extensions help to avoid code duplicates between your tests. Here’s how to set up your logging tests in two steps:
Step 2: Use that rule to assert against your log statement with logback or log4j2
Testing Log Statements Using Junit 4 Rules in Two Steps
JUnit 4 rules help to avoid code duplication by extracting the common test code away from the test classes. In our example, we don’t want to duplicate the code for adding a test appender to our logger in every test class.
Step 2: Use that rule to assert against your log statements using logback or log4j2.
With these approaches, you can assert that your log statements have been called with a message and level that you expect.
Conclusion
The Spring Boot Logging Starter provides everything you need to quickly get started, whilst allowing full control when you need it. We’ve looked at how most logging concerns (formatting, destinations, cross-cutting logging, context and unit tests) can be abstracted away from your core application code.
Any global changes to your logging can be done in one place, and the classes for the rest of your application don’t need to change. At the same time, unit tests for your log statements provide you with reassurance that your log statements are being fired after making any alterations to your business logic.
These are my top 5 tips for configuring Spring Boot Logging. However, when your logging configuration is set up, remember that your logs are only ever as good as the content you put in them. Be mindful of the content you are logging, and make sure you are using the right logging levels.
Apache Log4j 2 is a successor of Log4j 1.x (who would have guessed? :p).
Log4j 2 provides a significant improvement in performance compared to its predecessor. It contains asynchronous loggers and supports multiple APIs including SLF4J, commons logging, and java.util.loggging.
In this article, you’ll learn how to integrate and configure Log4j 2 in Spring Boot applications. You’ll configure different types of appenders including RollingFileAppender and SMTPAppender. You’ll also learn how to use Async logging capabilities provided by Log4j 2.
The idea is to build a simple Spring Boot application from scratch and demonstrate how to go about integrating and configuring Log4j 2 in the app.
So, Let’s get started!
Creating the Project
Let’s use Spring Boot CLI to generate the project. If you don’t have Spring Boot CLI installed, I highly encourage you to do so. Check out the Official Spring Boot documentation for any help with the installation.
Fire up your terminal and type the following command to generate the project –
spring init --name=log4j2-demo --dependencies=web log4j2-demo
Once the project is generated, import it into your favorite IDE. The project’s directory structure should look like this –
Adding Log4j2
All the Spring Boot starters depend on spring-boot-starter-logging, which uses Logback by default. For using Log4j2, you need to exclude spring-boot-starter-logging and add spring-boot-starter-log4j2 dependency.
Open pom.xml file and add the following snippet to the <dependencies> section –
Spring Boot automatically configures Log4j if it finds a file named log4j2.xml or log4j2.json or log4j2.yaml in the classpath.
In this article, we’ll configure log4j 2 using XML. Create a new file log4j2.xml inside src/main/resources directory, and add the following configuration to it –
The above configuration defines a simple ConsoleAppender and declares two loggers – an application specific logger and the the root logger.
Using Log4j 2 in the app
Let’s add some logging code to check our logger configuration. Open Log4j2DemoApplication.java and replace it with the following code –
package com.example.log4j2demo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Log4j2DemoApplication implements ApplicationRunner {
private static final Logger logger = LogManager.getLogger(Log4j2DemoApplication.class);
public static void main(String[] args) {
SpringApplication.run(Log4j2DemoApplication.class, args);
}
@Override
public void run(ApplicationArguments applicationArguments) throws Exception {
logger.debug("Debugging log");
logger.info("Info log");
logger.warn("Hey, This is a warning!");
logger.error("Oops! We have an Error. OK");
logger.fatal("Damn! Fatal error. Please fix me.");
}
}
We have added 5 simple logs of different log levels. When you run the app, it logs everything on the console.
Adding a Rolling File Appender
If you want your logs to be written to a file, then you can use a RollingFile appender. RollingFile appender creates a new file whenever the log file reaches a certain threshold specified by the triggering policy.
It stores the old log files with names matching the pattern specified by the filePattern parameter –
In the above RollingFile configuration, I’ve specified a SizeBasedTriggeringPolicy which will roll files over when the size reaches 10MB. The <DefaultRollOverStrategy max="10" /> element specifies the maximum number of log files that will be kept.
There is another common triggering policy called TimeBasedTriggeringPolicy which is used commonly in Log4j2. You can use TimeBasedTriggeringPolicy to specify how often a rollover should occur based on the most specific time unit in the date/time pattern specified in the filePattern attribute.
Here is how you can use the TimeBasedTriggeringPolicy in the above example to roll files over every day –
The interval attribute specifies the frequency of rollover. So if you want to roll files over every week, you can specify interval="7".
In the above example, the date/time pattern of the file is {yyy-MM-dd}, where the most specific time unit is dd (date). Therefore the TimeBasedTriggeringPolicy roll files over based on date. If the date/time pattern was yyy-MM-dd-HH, the rollover would occur based on hour.
Finally, To use the RollingFile appender, you need to add the above RollingFile configuration to the <Appenders> section inside log4j2.xml, and configure one of your loggers to use it like so –
Note that, for SMTP appender to work, you need to include spring-boot-starter-mail dependency to your pom.xml file –
<!-- Needed for SMTP appender -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
Asynchronous Logging
Log4j2 Supports Async loggers. These loggers provide a drastic improvement in performance compared to their synchronous counterparts.
Async Loggers internally use a library called Disruptor for asynchronous logging.
We need to include Disruptor dependency for using async loggers. Add the following to your pom.xml file –
<!-- Needed for Async Logging with Log4j 2 -->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.6</version>
</dependency>
Now you can either make all Loggers asynchronous, or create a mix of sync and async loggers.
1. Making all Loggers Asynchronous
Making all loggers asynchronous is very easy. You just need to set the SystemProperty Log4jContextSelector to org.apache.logging.log4j.core.async.AsyncLoggerContextSelector.
You can do that by adding the System Property at runtime like so –
You don’t need to add any SystemProperty when you’re using <AsyncLogger> element. Just add the above loggers to your log4j2.xml file and you’re ready to go.
Conclusion
Congratulations folks! In this article, we learned how to integrate and configure Log4j 2 in Spring Boot apps. We also configured different types of appenders like ConsoleAppender, RollingFile Appender, and SMTP Appender. Finally, we learned how to use Async loggers provided by Log4j2.
Given an array of integers, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Example:
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: The subarray [4,-1,2,1] has the largest sum = 6.
Maximum Contiguous Subarray Sum solution in Java
This problem can be solved using Kadane’s algorithm in O(n) time complexity.
The algorithm iterates over all the elements of the array (nums) and computes the maximum sum ending at every index (maxEndingHere). Here is how maxEndingHere is calculated:
Initialize maxEndingHere to nums[0]
Iterate through the array (1..n). For every iteration:
If maxEndingHere + nums[i] < nums[i], that means the previous max was negative and therefore we reset maxEndingHere to nums[i].
Otherwise, we set maxEndingHere = maxEndingHere + nums[i]
We also keep a variable maxSoFar which indicates the maximum sum found so far. And, with every iteration, we check if the current max (maxEndingHere) is greater than maxSoFar. If yes, then we update the value of maxSoFar.
Here is the complete solution:
import java.util.Scanner;
class MaximumSubarray {
private static int findMaxSubarraySum(int[] nums) {
int n = nums.length;
int maxSoFar = nums[0];
int maxEndingHere = nums[0];
for(int i = 1; i < n; i++) {
if(maxEndingHere + nums[i] < nums[i]) {
maxEndingHere = nums[i];
} else {
maxEndingHere = maxEndingHere + nums[i];
}
if(maxEndingHere > maxSoFar) {
maxSoFar = maxEndingHere;
}
}
return maxSoFar;
}
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
int n = keyboard.nextInt();
int[] nums = new int[n];
for(int i = 0; i < n; i++) {
nums[i] = keyboard.nextInt();
}
System.out.println(findMaxSubarraySum(nums));
}
}
It’s also possible to find out the start and end indices of the maximum contiguous subarray. Here is a modification of the above program which does that and prints the subarray –
import java.util.Scanner;
class MaximumSubarray {
private static int[] findMaxSubarrayIndices(int[] nums) {
int n = nums.length;
int maxSoFar = nums[0];
int maxEndingHere = nums[0];
int currentStart = 0, maxStart = 0, maxEnd = 0;
for(int i = 1; i < n; i++) {
if(maxEndingHere + nums[i] < nums[i]) {
maxEndingHere = nums[i];
currentStart = i;
} else {
maxEndingHere = maxEndingHere + nums[i];
}
if(maxEndingHere > maxSoFar) {
maxSoFar = maxEndingHere;
maxStart = currentStart;
maxEnd = i;
}
}
return new int[]{maxStart, maxEnd};
}
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
int n = keyboard.nextInt();
int[] nums = new int[n];
for(int i = 0; i < n; i++) {
nums[i] = keyboard.nextInt();
}
int[] indices = findMaxSubarrayIndices(nums);
int sum = 0;
System.out.print("Max contiguous subarray: ");
for(int i = indices[0]; i <= indices[1]; i++) {
System.out.print(nums[i] + " ");
sum += nums[i];
}
System.out.println();
System.out.println("Max contiguous subarray sum: " + sum);
}
}
It provides Spring Boot support in Maven, letting us package executable jar or war archives and run an application “in-place”. To use it, we must use Maven 3.2 (or later).
The plugin provides several goals to work with a Spring Boot application:
spring-boot:repackage: create a jar or war file that is auto-executable. It can replace the regular artifact or can be attached to the build lifecycle with a separate classifier.
spring-boot:run: run your Spring Boot application with several options to pass parameters to it.
spring-boot:start and stop: integrate your Spring Boot application to the integration-test phase so that the application starts before it.
spring-boot:build-info: generate a build information that can be used by the Actuator.