What is Abstract class in Java and popular interview questions?

What is Abstract Class?
An abstract class is a class that is incomplete, or to be considered incomplete.

You can declare abstract methods for which non abstract subclass has to provide implementation or it'll give compile-time error. "Methods that are declared but not yet implemented."

Also you can provide method implementation in abstract class itself. It can be used from subclass. You can override these method in its subclass.

Source code (Mobile.java)
import java.util.Date;
public abstract class Mobile {

    /**
     * Sub class has to provide implementation for method `call()`
     */ 
    public abstract void call();

    /**
     * Sub class has to provide implementation for method `sms()`
     */ 
    public abstract void sms();

    /**
     * We've provided implementation for current time.
     */
    public Date currentTime(){
     return new Date();
    }
}
Source code (SmartMobile.java)
public class SmartMobile extends Mobile{
 
    public void call(){
     // provide implementation
    }

    public void sms(){
     // provide implementation
    }
}
Source code (Main.java)
public class Main(){
    public static void main(String[] args){
     /** You can not instantiate abstract class. 
      * Following line will cause Compile-Time error 
      */
     // Mobile mobile = new Mobile();

     Mobile smartMobile = new SmartMobile();
    }
}

Now lets discuss behavior of abstract class via question-answer. These are the popular abstract class interview questions .

Question: Can we instantiate abstract class?
Answer: No. We can not instantiate abstract class. Its restricted by Java.

Question: Why does abstract class have constructor if we can not instantiate? 
Answer: Constructor in abstract class used to initialize properties/fields of abstract class via not abstract sub-class.

Question: When constructor of abstract class called?
Answer: When sub-class instantiated, constructor of abstract class is called.

Question: Can we mark constructor as abstract?
Answer: No

Question: Is it compulsory for abstract class to have at least one abstract method?
Answer: No its not compulsory. You can create abstract class with or without abstract methods.

Question: Can we declare abstract method as private? 
Answer: No. If abstract method is private then its not visible/accessible in its sub-class so it can not provide its implementation. However you can make abstract method protected.

Question: Why final and abstract can not be used at a time? 
Answer: When class or method marked with final means value or implementation provided and you don't want it to be changed while abstract means implementation asked to provide.

Simply it contradicts with each other.

Question: Can we declare abstract class or method as static?
Answer: No. static can be called without creating object and it contains implementation or value. abstract means implementation asked to provide. Its same as final.

Simply it contradicts with each other.

Question: Can we declare inner class as abstract?
Answer: Yes

Question: Can abstract method include throws in its declaration?
Answer: Yes

Question: Can we mark abstract method as synchronized?
Answer: No. However sub-class which override the method can be synchronized.
public abstract class Demo{
    public abstract void test();
}

public class DemoImpl extends Demo{
    @Override
    public synchronized void test(){
        //implementation
    }
}

Question: Can we use abstract class as member of another abstract class?
Answer: Yes. Its same as declaring other class as member(variable).

Reference
Difference between Abstract class and Interface in Java

How to run MySQL Server in docker?

MySQL in Docker

In my previous article we understood Why Docker and What is Docker? Now lets see how you launch MySQL in Docker.

Prerequisite
Docker must be installed in your local system.

Step 1: Open terminal in root mode. Launch MySQL by following command. It'll download MySQL DockerImage if not available and then start it.
root@vicky:/home/vicky# docker run --name localmysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql
Unable to find image 'mysql:latest' locally
latest: Pulling from library/mysql
6ae821421a7d: Pull complete 
a9e976e3aa6d: Pull complete 
e3735e44a020: Pull complete 
bfd564e9483f: Pull complete 
df705f26e488: Pull complete 
0c5547f73d62: Pull complete 
f437382cf8a1: Pull complete 
b8e2d50f1513: Pull complete 
e2e3c9928180: Pull complete 
b60db6d282cd: Pull complete 
1d32deab69c6: Pull complete 
408a40cd2e9c: Pull complete 
Digest: sha256:a571337738c9205427c80748e165eca88edc5a1157f8b8d545fa127fc3e29269
Status: Downloaded newer image for mysql:latest
89911662a4793d0468427919d395535e05a3b3004aeb8173cd4d9eaede30fa3a
Step 2: Verify MySQL is running or not by executing following command.
root@vicky:/home/vicky# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
89911662a479        mysql               "docker-entrypoint..."   6 minutes ago       Up 6 minutes        0.0.0.0:3306->3306/tcp, 33060/tcp   localmysql
Step 3: Enter into Docker MySQL app by executing following command.
root@vicky:/home/vicky# docker exec -ti localmysql bash
Step 4: You are into MySQL app. You can now connect and execute to MySQL commands on it.
root@89911662a479:/# mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.15 MySQL Community Server - GPL

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY 'root';
Query OK, 0 rows affected (0.05 sec)

mysql> CREATE DATABASE javaquery;
Query OK, 1 row affected (0.08 sec)

mysql> use javaquery;
Database changed

mysql> CREATE TABLE demo(id int, name varchar(100), email varchar(250));
Query OK, 0 rows affected (0.19 sec)

mysql> INSERT INTO demo(id, name, email) values(1, 'Vicky Thakor', 'vicky.thakor@javaquery.com');
Query OK, 1 row affected (0.05 sec)

mysql> SELECT * FROM demo;
+------+--------------+----------------------------+
| id   | name         | email                      |
+------+--------------+----------------------------+
|    1 | Vicky Thakor | vicky.thakor@javaquery.com |
+------+--------------+----------------------------+
1 row in set (0.00 sec)

mysql> exit
Bye
Step 5: Exit from container
root@89911662a479:/# exit
exit
Step 6: Stop MySQL container
root@vicky:/home/vicky# docker container stop localmysql
localmysql
Step 7: Remove MySQL container from docker engine.
root@vicky:/home/vicky# docker container rm localmysql
localmysql
Step 8: List docker images.
root@vicky:/home/vicky# docker images -a
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mysql               latest              81f094a7e4cc        47 hours ago        477MB
Step 9: Remove MySQL completely from Docker.
root@vicky:/home/vicky# docker rmi 81f094a7e4cc
Untagged: mysql:latest
Untagged: mysql@sha256:a571337738c9205427c80748e165eca88edc5a1157f8b8d545fa127fc3e29269
Deleted: sha256:81f094a7e4ccc963fde3762e86625af76b6339924bf13f1b7bd3c51dbcfda988
Deleted: sha256:77dac193858f3954c3997272aabbad794166770b735ea18c313cd920c6f9ae56
Deleted: sha256:29c7593e2c24df6b8a0c73c4445dce420a41801bb28f1e207c32d7771dfb2585
Deleted: sha256:5b0034d0389c5476c01ad2217fc3eddfcceb7fb71489fa266aac13c28b973bb5
Deleted: sha256:a8380edd959f5f457dfaff93b58bd9926cd7226fc7cfade052459bcaecf5404b
Deleted: sha256:75082d1a98ce7ef9eb053ed89644e09c38b4ebd6c964ec3eb050c637480a2874
Deleted: sha256:afa9c09812bcbc0960c0db6d5c1b3af6286097935e4aa46153b4538ad7082e4f
Deleted: sha256:7d3a170fc2a4187c57e941e4f37913add9034ac7e44f658630d38bc617b673b9
Deleted: sha256:1414c04de349b69ee9d1a593d766a275b92b1a01e4c440092ccde60b1ff8e5d9
Deleted: sha256:bcf08b24b02cc14c6a934d7279031a3f50bc903d903a2731db48b8cb6a924300
Deleted: sha256:81b6eebc1d362d1ca2a888172e315c4e482e0e888e4de4caef3f9e29a3339b78
Deleted: sha256:2c5c6956c8c5752b2034f6ab742040b574d9e3598fbd0684d361c8fc9ccb3554
Deleted: sha256:0a07e81f5da36e4cd6c89d9bc3af643345e56bb2ed74cc8772e42ec0d393aee3

Why Docker and What is Docker?

docker logo

Why Docker?
As a developer, Have you ever run into situations like...

  • Code is working in local system, ain't working on production/staging server.
  • Software(apache, php, etc...) upgrade on production/staging server crashed your code.
  • Require separate environment of your website/server to test newly developed feature.
All these problems of Software Development Life Cycle (SDLC) can be solved by docker. Now lets see...

What is Docker?
Docker is like virtual machine but unlike virtual machine, docker don't need separate Operating System on top of Host Operating System. Docker uses Host Operating System directly via Docker Engine to run applications.

Docker Containers vs Virtual Machines

How Software Development Life Cycle (SDLC) problems can be solved?
Using DockerFile, write your application specific environment to run.

What is DockerFile?
File contains environment specific configuration like: for development, for testing, for production, for release_v2.3.1, etc... This can be further drilled down as per your micro-services like...

  • dev-inventory-ui-php
  • dev-inventory-backend-java
  • dev-salesorder-ui-react
  • dev-salesorder-backend-spring

DockerFile
Sample docker file. No extension is required for this file.
FROM openjdk:8-jre
VOLUME /tmp
ADD your-app-main-1.0.jar destination-file-docker-app.jar
ENV JAVA_OPTS=""
ENTRYPOINT exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /destination-file-docker-app.jar
Docker in action
On local system you developed your application with Java version 8 now specify same version in DockerFile. Image built/created from this DockerFile will run Java version 8 in Container. So application will work as expected.

Now say if you upgrade your code for Java version 9. All you need to do is just update your DockerFile's Java version to 9. Docker will check that Java version 9 is needed and not available so it'll download Java version 9 and then run your application.

Lets say something goes wrong then you can launch container from your previous DockerImage of Java version 8. And you application is downgraded, no need to uninstall Java version 9 or any other software you added with new DockerFile.

By just writing DockerFile you can control your application's execution environment from local to development and development to production. You can also create multiple DockerFile for different environments as per your requirements.

  • Code execution will be same as local for production server.
  • This way you don't need to worry about upgrading/downgrading your server's environment.
  • Also same DockerImage can be used to launch new service. Docker will download all required software on server that are mentioned DockerFile. No overhead of configuring server for launching new service.

Advantages of Docker

  • Light weight compare to virtual machine.
  • Same DockerImage can run on local, Kubernetes, Amazon Web Service, Google Cloud, Microsoft Azure or any other cloud platform without changing anything in DockerFile.
  • Quickly start your application in Docker.

Other References:
How to run MySQL Server in docker?

Access modifiers in Java

Access modifiers in Java define the scope of class, constructor, methods and variable.

Why access modifiers?
The whole concept of access modifier is "What you want to expose from class".

There are total four access modifier public, protected, default and private in Java.

public - As name suggest any class, constructor, method and variable marked as public can be accessed within class, from sub/child-class, within same package or out of package. In other word "Can be accessed globally".

protected - Any Inner class, constructor, method and variable marked as protected can be accessed within class, from sub/child-class created in same package or different package, via object creation in same package.

You can not access protected Inner class, constructor, method and variable via object created in different package.

default - No access specifier defined for any Inner class, constructor, method and variable considered as default access level. It can be accessed within class, from sub/child-class created in same package only.

Default class, inner class, constructor, method and variables are not visible out side of package.

private - As name suggest any Inner class, constructor, method and variable marked as private can be accessed within same class only.


All access modifier's scope is given in following table.

Access Modifier same class same package
via sub-class/object
sub class in
different package
outside
the package
public Yes Yes Yes Yes
protected Yes Yes Yes No
default Yes Yes No No
private Yes No No No

Spring boot rest api with Mongodb CRUD examples

In previous articles we have seen Creating first rest api in spring-boot and also Passing and validating RequestParam in spring-boot rest api now we will take one step further by interacting with database. Also checkout Spring boot rest api with MySQL CRUD examples or browse all spring tutorials here.

build.gradle
update your build.gradle, add following dependencies and refresh the project, gradle will download the required dependencies(jar files).
//mongodb dependencies
compile('org.springframework.boot:spring-boot-starter-data-mongodb')
application.properties
Create new source folder under src/main/resources if not exist and add new file called application.properties. Add following lines for database connection.
#mongodb
spring.data.mongodb.host=127.0.0.1
spring.data.mongodb.port=27017
spring.data.mongodb.database=spring_boot_examples
spring.data.mongodb.username=root
spring.data.mongodb.password=root

Source code (User.java)
Note: In current example we are using spring boot 1.5.7.RELEASE which uses validations framework 1.1.0. @NotEmpty, @Email are part of package org.hibernate.validator. But spring boot 2.0.0 and above which supports validation framework 2.0 so @NotEmpty, @Email, etc... are now part of javax.validation.constraints.
import java.util.Date;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

/**
 * @author javaQuery
 * @since 2018-09-24
 * @github https://github.com/javaquery/spring-boot-examples
 */
@Document(collection = "users")
public class User{

    @Id
    public String id;

    @Field("first_name")
    @NotEmpty(message = "first_name can not be empty.")
    @Size(max = 100, message = "first_name can not be more than 100 characters.")
    private String firstName;
 
    @Field("last_name")
    @NotEmpty(message = "last_name can not be empty.")
    @Size(max = 100, message = "last_name can not be more than 100 characters.")
    private String lastName;
 
    @Field("email")
    @NotEmpty(message = "email can not be empty.")
    @Size(max = 100, message = "email can not be more than 100 characters.")
    private String email;
 
    @Field("password")
    @NotEmpty(message = "password can not be empty.")
    @Size(max = 100, message = "password can not be more than 100 characters.")
    private String password;
 
    @Field("created")
    private Long created = (new Date().getTime())/ 1000;
 
    @Field("modified")
    private Long modified  = (new Date().getTime())/ 1000;

    //getter-setter
}

Abstraction in Spring
Spring is all about abstraction via interfaces. Abstraction allows you to change the implementation without affecting caller method.

Repositories
The goal of Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores.
Spring Repository(interface) is abstraction for data access layer.

For example in your project you are going to use data storage like MySQL(RDBMS), MongoDb (NoSQL), etc... The caller class will interact to data storage using repository(interface) so for caller class it doesn't matter which storage you are using in implementation of repository either MySQL or MongoDb as long as data persist and retrieve back.

Here we are using MongoRepository for which spring will provide default implementation of MongoDb queries (INSERT, UPDATE, DELETE, SELECT) without writing it yourself.

Source code (MongoRepository.java)
import java.util.UUID;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.javaquery.examples.springboot.model.mongodb.User;

/**
 * @author javaQuery
 * @since 2018-09-24
 * @github https://github.com/javaquery/spring-boot-examples
 */
public interface UserMongoDbRepository extends MongoRepository<User, String>{
}
Now if you want to save record (User), all you got to do is call userMongoDbRepository.save(user);. Calling save on UserRepository will generate INSERT statement and execute it. Similarly you can perform update, select and delete.

Source code (Application.java)
Add @EnableMongoRepositories in your Application.java.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

/**
 * @author javaQuery
 * @since 2018-01-31
 * @github https://github.com/javaquery/spring-boot-examples
 */
@SpringBootApplication
@ComponentScan(basePackages = { "com.javaquery.examples.springboot.rest" })
@EnableMongoRepositories("com.javaquery.examples.springboot.model.mongodb.repositories")
public class Application {
    public static void main(String[] args) {
       SpringApplication.run(Application.class, args);
    }
}
  • @EnableMongoRepositories - Location(package) of your code which interact with database (repositories)

Services
Service is abstraction layer for application logic implementation.

Source code (UserMongoDbService.java)
UserMongoDbDTO / UserMongoDbDTO are request objects (JSON Payload). Source code is available under controller section.
import com.javaquery.examples.springboot.rest.dto.UserMongoDbDTO;
import com.javaquery.examples.springboot.rest.dto.UserUpdateDTO;

/**
 * @author javaQuery
 * @since 2018-09-24
 * @github https://github.com/javaquery/spring-boot-examples
 */
public interface UserMongoDbService {
    public UserMongoDbDTO addUser(UserMongoDbDTO userDTO);
    public UserMongoDbDTO getUser(String id);
    public UserMongoDbDTO updateUser(UserUpdateDTO userUpdateDTO, String id);
    public void deleteUser(String id);
}
Source code (UserMongoDbServiceImpl.java)
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.javaquery.examples.springboot.model.mongodb.User;
import com.javaquery.examples.springboot.model.mongodb.repositories.UserMongoDbRepository;
import com.javaquery.examples.springboot.rest.dto.UserMongoDbDTO;
import com.javaquery.examples.springboot.rest.dto.UserUpdateDTO;
import com.javaquery.examples.springboot.rest.exception.EntityNotFoundException;
import com.javaquery.examples.springboot.rest.service.UserMongoDbService;

/**
 * @author javaQuery
 * @since 2018-09-24
 * @github https://github.com/javaquery/spring-boot-examples
 */
@Service
public class UserMongoDbServiceImpl implements UserMongoDbService {

    @Autowired
    private UserMongoDbRepository userMongoDbRepository;

    @Override
    public UserMongoDbDTO addUser(UserMongoDbDTO userDTO) {
        /**
         * We are manually creating {@link User} object however there is mapper
         * available to convert to-from {@link UserDTO}.
         */
        User user = new User();
        user.setFirstName(userDTO.getFirstName());
        user.setLastName(userDTO.getLastName());
        user.setEmail(userDTO.getEmail());
        user.setPassword(userDTO.getPassword());
        userMongoDbRepository.save(user);

        /* set generated user id to response object */
        userDTO.setId(user.getId());
        userDTO.setPassword("");
        return userDTO;
    }

    @Override
    public UserMongoDbDTO getUser(String id) {
        User user = userMongoDbRepository.findOne(id);
        if (Objects.isNull(user)) {
            /* handle this exception using {@link RestExceptionHandler} */
            throw new EntityNotFoundException(User.class, id);
        }
        return new UserMongoDbDTO().build(user);
    }

    @Override
    public UserMongoDbDTO updateUser(UserUpdateDTO userUpdateDTO, String id) {
        User user = userMongoDbRepository.findOne(id);
        if (Objects.isNull(user)) {
            /* handle this exception using {@link RestExceptionHandler} */
            throw new EntityNotFoundException(User.class, id);
        }
        user.setFirstName(userUpdateDTO.getFirstName());
        user.setLastName(userUpdateDTO.getLastName());
        userMongoDbRepository.save(user);
        return new UserMongoDbDTO().build(user);
    }

    @Override
    public void deleteUser(String id) {
        userMongoDbRepository.delete(id);
    }
}

Controller (REST)
Controller is the entry point for all REST request.

Source code (UserMongoDbDTO.java)
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.javaquery.examples.springboot.model.mongodb.User;

/**
 * Object to interact using rest api.
 *
 * @author javaQuery
 * @since 2018-09-24
 * @github https://github.com/javaquery/spring-boot-examples
 */
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(Include.NON_NULL)
public class UserMongoDbDTO {

    /* used to send database id */
    private String id;

    @NotEmpty(message = "first_name can not be empty")
    @JsonProperty("first_name")
    private String firstName;

    @NotEmpty(message = "last_name can not be empty")
    @JsonProperty("last_name")
    private String lastName;

    @Email
    @JsonProperty("email")
    private String email;

    @NotEmpty(message = "password can not be empty")
    @Size(min = 6, message = "password must be at least 6 character")
    @JsonProperty("password")
    private String password;

    // getter - setter

    /**
     * We are manually creating {@link UserMongoDbDTO} object however there is
     * mapper available to convert to-from {@link User}.
     *
     * @param user
     * @return
     */
    public UserMongoDbDTO build(User user) {
        this.id = user.getId();
        this.firstName = user.getFirstName();
        this.lastName = user.getLastName();
        this.email = user.getEmail();
        return this;
    }
}

Source code (UserUpdateDTO.java)
import org.hibernate.validator.constraints.NotEmpty;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
 * Object to interact using rest api.
 * @author javaQuery
 * @since 2018-02-18
 * @github https://github.com/javaquery/spring-boot-examples
 */
public class UserUpdateDTO {
    @NotEmpty(message = "first_name can not be empty")
    @JsonProperty("first_name")
    private String firstName;
 
    @NotEmpty(message = "last_name can not be empty")
    @JsonProperty("last_name")
    private String lastName;
 
    // getter - setter
}

Source code (UserMongoDbController.java)
Http request POST, GET, PUT and POST are implemented in controller.
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.javaquery.examples.springboot.rest.dto.UserMongoDbDTO;
import com.javaquery.examples.springboot.rest.dto.UserUpdateDTO;
import com.javaquery.examples.springboot.rest.response.SuccessResponse;
import com.javaquery.examples.springboot.rest.service.UserMongoDbService;

/**
 * @author javaQuery
 * @since 2018-09-24
 * @github https://github.com/javaquery/spring-boot-examples
 */
@RestController
@RequestMapping("/api/user/mongodb")
public class UserMongoDbController {

    @Autowired
    private UserMongoDbService userMongoDbService;

    @PostMapping
    public ResponseEntity<UserMongoDbDTO> addUser(@Valid @RequestBody UserMongoDbDTO userDTO) {
        return ResponseEntity.ok(userMongoDbService.addUser(userDTO));
    }

    @GetMapping
    public ResponseEntity<UserMongoDbDTO> getUser(@RequestParam String id) {
        return ResponseEntity.ok(userMongoDbService.getUser(id));
    }

    @PutMapping
    public ResponseEntity<UserMongoDbDTO> updateUser(@Valid @RequestBody UserUpdateDTO userUpdateDTO, @RequestParam String id) {
        return ResponseEntity.ok(userMongoDbService.updateUser(userUpdateDTO, id));
    }

    @DeleteMapping
    public ResponseEntity<?> deleteUser(@RequestParam String id) {
        userMongoDbService.deleteUser(id);
        return ResponseEntity.ok(new SuccessResponse("deleted"));
    }
}
Note: Add updated EntityNotFoundException.java and RestExceptionHandler.java from github.

Request/Response
cURL POST http://localhost:8080/api/user/mongodb
-body {"first_name":"vicky","last_name":"thakor","email":"vicky.thakor@javaquery.com","password":"123456"}
-code 200
-body {"id":"5bada32eac0eb2127413b580","first_name":"vicky","last_name":"thakor","email":"vicky.thakor@javaquery.com","password":""}
cURL GET http://localhost:8080/api/user/mongodb?id=5bada32eac0eb2127413b580
-code 200
-body {"id":"5bada32eac0eb2127413b580","first_name":"vicky","last_name":"thakor","email":"vicky.thakor@javaquery.com"}
cURL PUT http://localhost:8080/api/user/mongodb?id=5bada32eac0eb2127413b580
-body {"first_name":"vickey","last_name":"thakor"}
-code 200
-body {"id":"5bada32eac0eb2127413b580","first_name":"vickey","last_name":"thakor","email":"vicky.thakor@javaquery.com"}
cURL DELETE http://localhost:8080/api/user/mongodb?id=5bada32eac0eb2127413b580
-code 200
-body {"message": "deleted"}

How to set value in Text Field of Jasper Report?


Source code (template_jasper_text_field.jrxml)
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.1.1.final using JasperReports Library version 6.1.1  -->
<!-- 2018-06-03T15:20:40 -->
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="template_jasper_text_field" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="67995913-5292-4c36-b77b-bab4e01b985c">
    <parameter name="billingAddress" class="java.lang.String"/>
    <parameter name="shippingAddress" class="java.lang.String"/>
    <queryString>
  <![CDATA[]]>
    </queryString>
    <background>
        <band splitType="Stretch"/>
    </background>
    <title>
        <band height="175" splitType="Stretch">
            <staticText>
                <reportElement x="0" y="0" width="100" height="20" uuid="6d933de8-de74-4b47-b2f9-9f16f8f80a13"/>
                <text><![CDATA[Billing Address:]]></text>
            </staticText>
            <textField>
                <reportElement x="0" y="20" width="200" height="100" uuid="353295e2-3e1e-4e8d-93f9-e3f659c95039"/>
                <textFieldExpression><![CDATA[$P{billingAddress}]]></textFieldExpression>
            </textField>
            <staticText>
                <reportElement x="320" y="0" width="100" height="20" uuid="3e9df9ea-5f99-4246-9982-f55a5bd7c305"/>
                <text><![CDATA[Shipping Address:]]></text>
            </staticText>
            <textField>
                <reportElement x="320" y="20" width="220" height="100" uuid="2c5f72d8-f571-4b00-a1fd-a4bbc500542d"/>
                <textFieldExpression><![CDATA[$P{shippingAddress}]]></textFieldExpression>
            </textField>
        </band>
    </title>
    <pageHeader>
        <band height="35" splitType="Stretch"/>
    </pageHeader>
    <columnHeader>
        <band height="61" splitType="Stretch"/>
    </columnHeader>
    <detail>
        <band height="125" splitType="Stretch"/>
    </detail>
    <columnFooter>
        <band height="45" splitType="Stretch"/>
    </columnFooter>
    <pageFooter>
        <band height="54" splitType="Stretch"/>
    </pageFooter>
    <summary>
        <band height="42" splitType="Stretch"/>
    </summary>
</jasperReport>

Source code (JasperReportTextFieldExample.java)
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;

/**
 * @author javaQuery
 * @since 2018-05-27
 * @github https://github.com/javaquery/Examples
 */
public class JasperReportTextFieldExample {

    public static void main(String[] args) {
        try {
            /* User home directory location */
            String userHomeDirectory = System.getProperty("user.home");
            /* Output file location */
            String outputFile = userHomeDirectory + File.separatorChar + "JasperReportTextFieldExample.pdf";

            /* Map to hold Jasper report Parameters */
            Map<String, Object> parameters = new HashMap<String, Object>();
            parameters.put("billingAddress", "Google LLC,\n1600 Amphitheatre Parkway Mountain View,\nCA 94043 USA");
            parameters.put("shippingAddress", "Google LLC,\n1600 Amphitheatre Parkway Mountain View,\nCA 94043 USA");

            /* Using compiled version(.jasper) of Jasper report to generate PDF */
            JasperPrint jasperPrint = JasperFillManager.fillReport("resources/com/javaquery/jasper/templates/template_jasper_text_field.jasper", parameters, new JREmptyDataSource());

            /* outputStream to create PDF */
            OutputStream outputStream = new FileOutputStream(new File(outputFile));
            /* Write content to PDF file */
            JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream);

            System.out.println("File Generated: " + outputFile);
        } catch (JRException ex) {
            ex.printStackTrace();
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        }
    }
}

Spring internationalization(i18n) example for response and errors

Nowadays,  your application has users from around the world. For ease of your user, you want them to use web application in their local language. You must consider internationalization (i18n) while creating your web application.

In following example we will learn how you can apply internationalization to your spring application. In my previous articles we learned Creating first rest api in spring-boot and you can browse all spring article for starter.

Language specific properties file
Create properties file under src/main/resource folder for individual language you want to support in your application. We create package locale under folder and placed all file in it.

messages_de.properties
springboot.hello=Hallo
springboot.customerror=benutzerdefinierte Fehlermeldung
messages_en.properties
springboot.hello=Hello
springboot.customerror=custom error message
messages_fr.properties
springboot.hello=Bonjour
springboot.customerror=message d'erreur personnalisé
messages_zh.properties
For Chinese character you have to convert character / word into Unicode. How to convert Chinese character or word to Unicode online?
springboot.hello=\u4f60\u597d
springboot.customerror=\u81ea\u5b9a\u4e49\u9519\u8bef\u6d88\u606f

Source code (ApplicationConfig.java)
Load your language properties file in spring context using ReloadableResourceBundleMessageSource.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * @author javaQuery
 * @since 2018-02-18
 * @github https://github.com/javaquery/spring-boot-examples
 */
@Configuration
public class ApplicationConfig extends WebMvcConfigurerAdapter{
    @Bean
    public ReloadableResourceBundleMessageSource messageSource(){
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("classpath:locale/messages");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }
 
    /**
     * Internationalization for parameter and payload validation messages. 
     * @return
     */
    @Bean
    public LocalValidatorFactoryBean validator() {
       LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
       bean.setValidationMessageSource(messageSource());
       return bean;
    }

    @Override
    public Validator getValidator() {
       return validator();
    }
}

Source code (Application.java)
Add ApplicationConfig.java file package com.javaquery.examples.springboot.main.config in Application.java for component scan.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

/**
 * @author javaQuery
 * @since 2018-01-31
 * @github https://github.com/javaquery/spring-boot-examples
 * 
 * @change message internationalization (locale)
 */
@SpringBootApplication
@ComponentScan(basePackages = { "com.javaquery.examples.springboot.rest",  "com.javaquery.examples.springboot.main.config"})
@EntityScan("com.javaquery.examples.springboot.model")
@EnableJpaRepositories("com.javaquery.examples.springboot.model.repositories")
public class Application {
    public static void main(String[] args) {
       SpringApplication.run(Application.class, args);
    }
}

Source code (LocaleController.java)
import java.util.Locale;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * Springboot internationalization example
 * @author javaQuery
 * @since 2018-04-06  
 */
@RestController
@RequestMapping("/api")
@Validated
public class LocaleController {
 
    @Autowired
    private MessageSource messageSource; 
 
    /**
     * Response internationalization.
     * @param name
     * @param locale
     * @return
     */
    @GetMapping("/locale")
    public ResponseEntity<?> sayHello(@RequestParam("name") String name, Locale locale){
       String localeHello = messageSource.getMessage("springboot.hello", null, locale);
       return ResponseEntity.ok(localeHello + " " + name);
    }
 
    /**
     * Validation parameter internationalization. 
     * @param firstname
     * @param lastname
     * @param notEmptyParam
     * @param locale
     * @return
     */
    @GetMapping("/locale/param")
    public ResponseEntity<?> parameterValidation(@Size(min = 1, max = 5, message = "firstname {javax.validation.constraints.Size.message}") @RequestParam("firstname") String firstname,
       @NotEmpty(message = "lastname {org.hibernate.validator.constraints.NotEmpty.message}") @RequestParam("lastname") String lastname,
       @NotEmpty(message = "{springboot.customerror}") String notEmptyParam, Locale locale){
         String localeHello = messageSource.getMessage("springboot.hello", null, locale);
         return ResponseEntity.ok(localeHello + " " + firstname + " " + lastname);
    }
}
We used properties file key springboot.hello to send language specific response of "Hello".

Internationalization for error messages
parameterValidation method demonstrate use of internationalization code for validation.
 - You can create your own custom code like {springboot.customerror}.
 - Use inbuilt codes. You find out internationalization code from source of annotation.


Enable Internationalization
To enable internationalization for http request send header accept-language in your request.

Request/Response
cURL POST localhost:8080/api/locale?name=vicky
-H 'accept-language: fr'
-code 200
-body Bonjour vicky
cURL POST localhost:8080/api/locale/param?firstname=VickyV&lastname=Thakor
-H 'accept-language: de'
-code 400
-body {"errors":["firstname muss zwischen 1 und 5 liegen","benutzerdefinierte Fehlermeldung"]}