The Runtime.getRuntime().availableProcessors() method returns the maximum number of processors available to the Java virtual machine, the value will never be smaller than one. Knowing the number of available processor you can use it for example to limit the number of thread in your application when you are writing a multi-thread code.
package org.kodejava.lang;
public class NumberProcessorExample {
public static void main(String[] args) {
final int processors = Runtime.getRuntime().availableProcessors();
System.out.println("Number of processors = " + processors);
}
}
When you use the Spring framework @Transactional annotation in your service layer you might want to see what is happening in your code related to database transaction. You want to see when a transaction is started, when it is committed or rollbacked.
To activate the log for transactional message you can add the following configurations in your application properties file. For example when using the JpaTransactionManager you can set the log level to DEBUG.
In this example we are going to build a simple search page using ZK framework and Spring Boot. We are going to use the latest available version of Spring Boot (3.0.0) and ZK Framework (9.6.0.2). So without taking more time let’s start by creating a new spring boot project with the following pom.xml. You can create the initial project using your IDE or spring initializr.
Create a Spring Boot project and add the following dependencies:
This properties file configure ZK application homepage and the prefix where the zul files are located. We also configure the datasource to our application database.
An entity that represent out record label with just two property of id and name. Getters and setters are generated by Lombok library, it also generated to equals() and hashcode() method, and also the toString() method.
package org.kodejava.zk.entity;
import jakarta.persistence.*;
import lombok.Data;
@Data
@Entity
public class Label {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
The LabelRepository.java definition.
Create the LabelRepository which extends the JpaRepository and JpaSpecificationExecutor interfaces.
AbstractSearchController.java a base search controller.
A base class that we can use to implements all the search page in an application. Basically it provides the method to search our application data. It defines a couple of abstract method that need to be implemented by the search controller classes such as what repository to use and the specification for searching the data. We can also define the default sort column and the direction of the data sorting.
package org.kodejava.zk.controller;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.VariableResolver;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Listbox;
@VariableResolver(org.zkoss.zkplus.spring.DelegatingVariableResolver.class)
public abstract class AbstractSearchController<T> extends SelectorComposer<Component> {
@Wire
protected Listbox listbox;
public abstract JpaSpecificationExecutor<T> getRepository();
public abstract Specification<T> getSpecification();
public abstract String getCacheKey();
protected String getDefaultSortColumn() {
return "id";
}
protected Sort.Direction getDefaultSortDirection() {
return Sort.Direction.ASC;
}
protected boolean getMultiple() {
return false;
}
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
search();
}
@Listen("onClick=#searchButton")
public void search() {
listbox.setVisible(true);
SearchListModel<T> model = new SearchListModel<>(getRepository(), getSpecification(), getCacheKey());
model.setMultiple(getMultiple());
model.setDefaultSortColumn(getDefaultSortColumn());
model.setDefaultSortDirection(getDefaultSortDirection());
listbox.setModel(model);
listbox.setActivePage(0);
}
@Listen("onOK=#searchForm")
public void onEnterPressed(Event event) {
search();
}
public int getPageSize() {
return SearchListModel.PAGE_SIZE;
}
}
SearchListModel.java
An implementation of ListModel, this class will query the database using the provided repository and specification. It read data page-by-page and cache it so when we navigating the Listbox page it doesn’t read the data that have already been cached.
package org.kodejava.zk.controller;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.zkoss.zk.ui.Execution;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zul.FieldComparator;
import org.zkoss.zul.ListModelList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
public class SearchListModel<T> extends ListModelList<T> {
public static final int PAGE_SIZE = 5;
private final JpaSpecificationExecutor<T> repository;
private final String cacheKey;
private long totalElements;
private Comparator<T> comparator;
private boolean ascending = false;
private final Specification<T> specification;
private Sort.Direction defaultSortDirection = Sort.Direction.ASC;
private String defaultSortColumn = "id";
public SearchListModel(JpaSpecificationExecutor<T> repository, Specification<T> specification, String cacheKey) {
this.repository = repository;
this.specification = specification;
this.cacheKey = cacheKey;
this.totalElements = repository.count(specification);
}
@Override
public T getElementAt(int index) {
Map<Integer, T> cache = getCache();
T target = cache.get(index);
if (target == null) {
Sort sort = Sort.by(getDefaultSortDirection(), getDefaultSortColumn());
if (comparator != null) {
FieldComparator fieldComparator = (FieldComparator) comparator;
String orderBy = fieldComparator.getRawOrderBy();
sort = Sort.by(ascending ? Sort.Direction.ASC : Sort.Direction.DESC, orderBy);
}
Page<T> pageResult = repository.findAll(specification, PageRequest.of(getPage(index), PAGE_SIZE, sort));
totalElements = pageResult.getTotalElements();
int indexKey = index;
for (T t : pageResult.toList()) {
cache.put(indexKey, t);
indexKey++;
}
} else {
return target;
}
target = cache.get(index);
if (target == null) {
throw new RuntimeException("element at " + index + " cannot be found in the database.");
} else {
return target;
}
}
@Override
public int getSize() {
return (int) totalElements;
}
@Override
public void sort(Comparator<T> comparator, boolean ascending) {
super.sort(comparator, ascending);
this.comparator = comparator;
this.ascending = ascending;
}
@SuppressWarnings("unchecked")
private Map<Integer, T> getCache() {
Execution execution = Executions.getCurrent();
Map<Integer, T> cache = (Map<Integer, T>) execution.getAttribute(cacheKey);
if (cache == null) {
cache = new HashMap<>();
execution.setAttribute(cacheKey, cache);
}
return cache;
}
private int getPage(int index) {
if (index != 0) {
return index / PAGE_SIZE;
}
return index;
}
public Sort.Direction getDefaultSortDirection() {
return defaultSortDirection;
}
public void setDefaultSortDirection(Sort.Direction defaultSortDirection) {
this.defaultSortDirection = defaultSortDirection;
}
public String getDefaultSortColumn() {
return defaultSortColumn;
}
public void setDefaultSortColumn(String defaultSortColumn) {
this.defaultSortColumn = defaultSortColumn;
}
}
LabelSearchController.java
Our label search page controller which extends from AbstractSearchController class. We provide the LabelRepository and the Specification to filter the data.
The code snippet below shows you a simple way to calculate days between two dates excluding weekends and holidays. As an example, you can use this function for calculating work days. The snippet utilize the java.time API and the Stream API to calculate the value.
What we do in the code below can be described as the following:
Create a list of holidays. The dates might be read from a database or a file.
Define filter Predicate for holidays.
Define filter Predicate for weekends.
These predicates will be use for filtering the days between two dates.
Define the startDate and the endDate to be calculated.
Using Stream.iterate() we iterate the dates, filter it based on the defined predicates.
Finally, we get the result as list.
The actual days between is the size of the list, workDays.size().
package org.kodejava.datetime;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class DaysBetweenDates {
public static void main(String[] args) {
List<LocalDate> holidays = new ArrayList<>();
holidays.add(LocalDate.of(2022, Month.DECEMBER, 26));
holidays.add(LocalDate.of(2023, Month.JANUARY, 2));
Predicate<LocalDate> isHoliday = holidays::contains;
Predicate<LocalDate> isWeekend = date -> date.getDayOfWeek() == DayOfWeek.SATURDAY
|| date.getDayOfWeek() == DayOfWeek.SUNDAY;
LocalDate startDate = LocalDate.of(2022, Month.DECEMBER, 23);
LocalDate endDate = LocalDate.of(2023, Month.JANUARY, 3);
System.out.println("Start date = " + startDate);
System.out.println("End date = " + endDate);
// Days between startDate inclusive and endDate exclusive
long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
System.out.println("Days between = " + daysBetween);
List<LocalDate> workDays = Stream.iterate(startDate, date -> date.plusDays(1))
.limit(daysBetween)
.filter(isHoliday.or(isWeekend).negate())
.toList();
long actualDaysBetween = workDays.size();
System.out.println("Actual days between = " + actualDaysBetween);
}
}
Running the code snippet above give us the following result:
Start date = 2022-12-23
End date = 2023-01-03
Days between = 11
Actual days between = 5
The following code example demonstrate how to export MySQL database schema into markdown table format. We get the table structure information by executing MySQL’s DESCRIBE statement.
The steps we do in the code snippet below:
Connect to the database.
We obtain the list of table name from the database / schema.
Executes DESCRIBE statement for each table name.
Read table structure information such as field, type, null, key, default and extra.
Write the information into markdown table format and save it into table.md.
And here are the complete code snippet.
package org.kodejava.jdbc;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class DescribeMySQLToMarkDown {
private static final String URL = "jdbc:mysql://localhost/kodejava";
private static final String USERNAME = "root";
private static final String PASSWORD = "";
public static void main(String[] args) {
String tableQuery = """
select table_name
from information_schema.tables
where table_schema = 'kodejava'
and table_type = 'BASE TABLE'
order by table_name;
""";
try (Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD)) {
Statement stmt = connection.createStatement();
ResultSet resultSet = stmt.executeQuery(tableQuery);
List<String> tables = new ArrayList<>();
while (resultSet.next()) {
tables.add(resultSet.getString("table_name"));
}
System.out.println(tables.size() + " tables found.");
try (BufferedWriter writer = new BufferedWriter(new FileWriter("table.md"))) {
for (String table : tables) {
System.out.println("Processing table: " + table);
Statement statement = connection.createStatement();
ResultSet descResult = statement.executeQuery("DESCRIBE " + table);
writer.write(String.format("Table Name: **%s**%n%n", table));
writer.write("| Field Name | Data Type | Null | Key | Default | Extra |\n");
writer.write("|:---|:---|:---|:---|:---|:---|\n");
while (descResult.next()) {
String field = descResult.getString("field");
String type = descResult.getString("type");
String nullInfo = descResult.getString("null");
String key = descResult.getString("key");
String defaultInfo = descResult.getString("default");
String extra = descResult.getString("extra");
String line = String.format("| %s | %s | %s | %s | %s | %s |%n",
field, type, nullInfo, key, defaultInfo, extra);
writer.write(line);
}
writer.write("\n<br/>\n<br/>\n");
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
This code snippet will produce something like below. I have tidy up the markdown for a better presentation.
Table Name: **books**
| Field Name | Data Type | Null | Key | Default | Extra |
|:-----------|:----------------|:-----|:----|:--------|:---------------|
| id | bigint unsigned | NO | PRI | null | auto_increment |
| isbn | varchar(30) | NO | | null | |
<br/>
<br/>
In the following code snippet we will convert java.util.Map object into JSON string and convert back the JSON string into Java Map object. In this example we will be using the Jackson library.
To convert from Map to JSON string the steps are:
Create a map of string keys and values.
Create an instance of Jackson ObjectMapper.
To convert map to JSON string we call the writeValueAsString() method and pass the map as argument.
Running the code snippet above will print the following output:
json = {"RED":"#FF0000","WHITE":"#FFFFFF","BLUE":"#0000FF","BLACK":"#000000","YELLOW":"#FFFF00","GREEN":"#008000"}
Map:
RED = #FF0000
WHITE = #FFFFFF
BLUE = #0000FF
BLACK = #000000
YELLOW = #FFFF00
GREEN = #008000
The simplest way to get the Java version is by running the java -version command in your terminal application or Windows command prompt. If Java is installed and available on your path you can get information like below.
java -version
java version "17" 2021-09-14 LTS
Java(TM) SE Runtime Environment (build 17+35-LTS-2724)
Java HotSpot(TM) 64-Bit Server VM (build 17+35-LTS-2724, mixed mode, sharing)
Using System Properties
But if you want to get Java version from your Java class or application you can obtain the Java version by calling the System.getProperty() method and provide the property key as argument. Here are some property keys that related to Java version that you can read from the system properties.
Since JDK 9 we can use Runtime.version() to get Java runtime version. The feature(), interim(), update and patch() methods of the Runtime.Version class are added in JDK 10. These methods is a replacement for the major(), minor() and security() methods of JDK 9.
Below is the code snippet that demonstrate the Runtime.version().
In the following code snippet we will convert CSV into JSON string using Jackson JSON library. A comma-separated values is a delimited text, it uses comma to separate values. It starts with header on the first line, that will be the JSON key. Each subsequence lines is the data of the csv, which also contains several values separated by comma.
Let’s see the code how to do this in Jackson.
package org.kodejava.jackson;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public class CsvToJson {
public static void main(String[] args) {
// Comma delimited text created using text blocks
String countries = """
ISO, CODE, NAME\s
CZE, CZ, Czech Republic\s
DNK, DK, Denmark\s
DJI, DJ, Djibouti\s
DMA, DM, Dominica\s
ECU, EC, Ecuador
""";
CsvSchema csvSchema = CsvSchema.emptySchema().withHeader();
CsvMapper csvMapper = new CsvMapper();
try {
List<Map<?, ?>> list;
try (MappingIterator<Map<?, ?>> mappingIterator = csvMapper.reader()
.forType(Map.class)
.with(csvSchema)
.readValues(countries)) {
list = mappingIterator.readAll();
}
ObjectMapper objectMapper = new ObjectMapper();
String jsonPretty = objectMapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(list);
System.out.println(jsonPretty);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Here are the explanation of the code above:
Define a csv string, in this case we have a list of countries.
Create an empty schema of CsvSchema to process csv with header line.
Create an instance of CsvMapper, a specialized type of ObjectMapper.
Read and parse csv values into List<Map<?, ?>>.
We use the ObjectMapper create a pretty-printed JSON from the list object.
In the following code snippet you will see how to convert a CSV file into JSON file and vice versa. We use the JSON-Java library CDL class to convert between CSV and JSON format. The CDL class provide the toJSONArray(String) and toString(JSONArray) methods that allows us to do the conversion between data format.
In the CSV file, the first line in the file will be use as the keys to the generated JSON string. On the other way around, the JSON string keys will be written on the first line of the CSV file as the column header.
Convert CSV file to JSON file.
package org.kodejava.json;
import org.json.CDL;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.stream.Collectors;
public class CsvFileToJsonFile {
public static void main(String[] args) {
// Read csv data file and store it in a string
InputStream is = CsvFileToJsonFile.class.getResourceAsStream("/data.csv");
String csv = new BufferedReader(
new InputStreamReader(Objects.requireNonNull(is), StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
try {
// Convert csv text to JSON string, and save it
// to a data.json file.
String json = CDL.toJSONArray(csv).toString(2);
Files.write(Path.of("data.json"), json.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
What we do in the snippet above:
Get cvs data as InputStream from the resources directory.
We use the BufferedReader and InputStreamReader to iterate and read the InputStream and return it as a string.
Convert the csv string into JSON string using CDL.toJSONArray().
We can pretty-printed the JSON string by specifying an indentFactor to the toString() method of the JSONArray object.