Builder Design Pattern in Java

The builder pattern, as the name suggest, we can use this pattern to build/construct complex objects. We should use this pattern when we want to construct same type of immutable objects with different sets of attributes.

Goal of Builder Design Pattern (https://en.wikipedia.org/wiki/Builder_pattern)
The goal of Builder design pattern is to separate the construction of a complex object from its representation so the same construction process can create different representations.
 
Now lets understand the builder design pattern with real world example. We all have Contact details in our mobile. Now lets construct Contact object with different sets of attributes.
 
For any Contact in our mobile, name is required data however email, mobile number, address, birthday are optional attributes. Now if we want to create immutable Contact object then constructor would look like as follow.

Source code (Contact.java)
/**
 * @author javaQuery
 * @date 2021-09-07
 * @Github: https://github.com/javaquery/Examples
 */
public Contact{
	private String name;
	private String email; // can be list of emails
	private String mobile; // can be list fo mobiles
	private String address;
	private Date birthday;

	public Contact(String name, String email, String mobile, String address, Date birthday){
		this.name = name;
		this.email = email; 
		this.mobile = mobile; 
		this.address = address;
		this.birthday = birthday;
	}	
}
In above example if you notice that even though email, mobile, etc... are optional to construct Contact object we have to pass null value for optional attributes. What other option we can think of is to create different constructor as per the requirements.
	public Contact(String name, String email){...}
	public Contact(String name, String mobile){...}
	public Contact(String name, String email, String mobile){...}
	public Contact(String name, String email, String mobile, String address){...}
	...
	...
Now what if we introduce another attribute anniversary? Contact object constructor would become more complex and hard to handle.
 
Builder pattern in action
Now lets use builder pattern to construct Contact object. We will take help of inner Builder class to construct the Contact object.

Source code (Contact.java)
import java.util.Date;

/**
 * @author javaQuery
 * @date 2021-09-21
 * @Github: https://github.com/javaquery/Examples
 */
public class Contact {
    private final String name;
    private final String email; // can be list of emails
    private final String mobile; // can be list fo mobiles
    private final String address;
    private final Date birthday;

    public Contact(Builder builder) {
        this.name = builder.name;
        this.email = builder.email;
        this.mobile = builder.mobile;
        this.address = builder.address;
        this.birthday = builder.birthday;
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }

    public String getMobile() {
        return mobile;
    }

    public String getAddress() {
        return address;
    }

    public Date getBirthday() {
        return birthday;
    }

    @Override
    public String toString() {
        return "Contact{" +
                "name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", mobile='" + mobile + '\'' +
                ", address='" + address + '\'' +
                ", birthday=" + birthday +
                '}';
    }

    public static class Builder{
        private final String name;
        private String email; // can be list of emails
        private String mobile; // can be list fo mobiles
        private String address;
        private Date birthday;

        public Builder(String name) {
            this.name = name;
        }

        public Builder email(String email){
            this.email = email;
            return this;
        }

        public Builder mobile(String mobile){
            this.mobile = mobile;
            return this;
        }

        public Builder address(String address){
            this.address = address;
            return this;
        }

        public Builder birthday(Date birthday){
            this.birthday = birthday;
            return this;
        }

        public Contact build(){
            return new Contact(this);
        }
    }
}
  
Source code (BuilderMain.java)
Using Builder class to construct the Contact object.
import java.util.Date;

public class BuilderMain {
    public static void main(String[] args) {
        Contact contactVicky = new Contact.Builder("Vicky")
                .email("vicky.thakor@javaquery.com")
                .build();
        System.out.println(contactVicky);

        Contact contactKrupa = new Contact.Builder("Krupa")
                .birthday(new Date())
                .build();
        System.out.println(contactKrupa);
    }
}

Builder pattern in JDK
java.lang.StringBuilder and java.lang.StringBuffer are widely known class which uses Builder Design Pattern. Using method append(....) you can construct the final object as per your requirements.
 
 
 

org.redisson.client.RedisException: Unexpected exception while processing command

  org.redisson.client.RedisException: org.redisson.client.RedisException: Unexpected exception while processing command
	at jdk.internal.reflect.GeneratedConstructorAccessor358.newInstance(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:600)
	at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:678)
	at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:737)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:661)
	at jdk.internal.reflect.GeneratedMethodAccessor1318.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.servlet.resource.ResourceUrlEncodingFilter.doFilter(ResourceUrlEncodingFilter.java:65)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
	at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:764)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:888)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: org.redisson.client.RedisException: Unexpected exception while processing command
	at org.redisson.command.CommandAsyncService.convertException(CommandAsyncService.java:352)
	at org.redisson.command.CommandAsyncService.get(CommandAsyncService.java:149)
	at org.redisson.RedissonObject.get(RedissonObject.java:81)
	at org.redisson.RedissonMap.get(RedissonMap.java:618)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
	at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
Caused by: java.io.IOException: java.lang.ClassNotFoundException: com.xxx.xxx.xxx
	at org.redisson.codec.MarshallingCodec$3.decode(MarshallingCodec.java:153)
	at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:359)
	at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:178)
	at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:117)
	at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:102)
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
	at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1533)
	at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1282)
	at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1329)
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.ClassNotFoundException: com.xxx.xxx.xxx
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:398)
	at org.jboss.marshalling.AbstractClassResolver.loadClass(AbstractClassResolver.java:129)
	at org.jboss.marshalling.AbstractClassResolver.resolveClass(AbstractClassResolver.java:110)
	at org.jboss.marshalling.river.RiverUnmarshaller.doReadClassDescriptor(RiverUnmarshaller.java:1033)
	at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1366)
	at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:283)
	at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:216)
	at org.jboss.marshalling.AbstractObjectInput.readObject(AbstractObjectInput.java:41)
	at org.redisson.codec.MarshallingCodec$3.decode(MarshallingCodec.java:151)
	... 32 common frames omitted
  
To fix the exception you need to set codec for your redisson. By using org.redisson.codec.SerializationCodec I was able to resolve the issue.
Config config = new Config();
config.setCodec(new org.redisson.codec.SerializationCodec());
 

Exception Handling with Method Overriding in Java


In our day to day programming we use method overriding widely. Have you ever considered how exception handling rule works in method overriding? Lets see how it works in Java with example. 
 
RULE 1. Super class method does not declare any exception in its method signature.
If super class method does not declared any exception in its method signature then sub-class's over ridden method can not declare any checked exception however it can declare any unchecked/RuntimeException. Following example demonstrate the first rule of exception. 
 
Source code (SuperClassExceptionRule1.java)
/**
 * Example of SuperClassExceptionRule1 in java.
 * @author javaQuery
 * @date 2021-09-07
 * @Github: https://github.com/javaquery/Examples
 */
public class SuperClassExceptionRule1 {

    public void methodWithoutException(){
        System.out.println("methodWithoutException");
    }

    public static void main(String[] args) {
        System.out.printf("SuperClassExceptionRule1");
    }

    public class ChildClassExceptionRule1 extends SuperClassExceptionRule1{

//        Compile time error when tried to throw checked exception
//        @Override
//        public void methodWithoutException() throws Exception{
//            super.methodWithoutException();
//        }

        // Allowed to throw unchecked exception (i.e Any RuntimeException)
        @Override
        public void methodWithoutException() throws RuntimeException{
            super.methodWithoutException();
        }
    }
}
RULE 2. Super class method declared exception in its method signature.
If super class method declared any exception in its method signature then sub-class's over ridden method can declare same exception, any child/sub-class exception or no exception however you can not declare parent exception. Following example demonstrate the second rule of exception.
 
Source code (SuperClassExceptionRule2.java)
/**
 * Example of SuperClassExceptionRule2 in java.
 * @author javaQuery
 * @date 2021-09-07
 * @Github: https://github.com/javaquery/Examples
 */
public class SuperClassExceptionRule2 {

    public void methodWithException() throws IllegalArgumentException{
        System.out.println("methodWithException");
    }

    public static void main(String[] args) {
        System.out.printf("SuperClassExceptionRule2");
    }

    public class ChildClassExceptionRule2 extends SuperClassExceptionRule2 {

//        Compile time error when tried to throw parent exception
//        @Override
//        public void methodWithException() throws Exception{
//            super.methodWithException();
//        }

        // Allowed to throw original exception (IllegalArgumentException)
        // or child exception of IllegalArgumentException
        @Override
        public void methodWithException() throws NumberFormatException{
            super.methodWithException();
        }
    }

    public class ChildClassExceptionRule22 extends SuperClassExceptionRule2 {

        // Allowed not to throw any exception
        @Override
        public void methodWithException(){
            super.methodWithException();
        }
    }
}

What is the difference between Error and Exception in Java?


Errors and Exceptions are the subclasses of Throwable. However it hold different context for any Java program.
 
Errors result from failures detected by the Java Virtual Machine, such as OutOfMemoryError, StackOverflowError, etc... Most simple programs do not try to handle errors. For errors programs are not expected to recover. Mostly errors results from lack of resources provided to program. An Internal error or resource limitation errors are subclasses of VirtualMachineError.

Source code (StackOverflowErrorExample.java)
/**
 * Example of StackOverflowError in java.
 * @author javaQuery
 * @date 2021-09-07
 * @Github: https://github.com/javaquery/Examples
 */
public class StackOverflowErrorExample {
    private static void recursion(int i){
        if(i == 0){
            System.out.println("Not reachable code");
        }else{
            recursion(i++);
        }
    }

    public static void main(String[] args) {
        recursion(10);
    }
}
  
Exception results when constraints are violated in program. Exception can be checked exception or unchecked exception. For exceptions, programs are expected to recover. Exception can occur at compile time (checked exception: FileNotFoundException) and at run time (unchecked exception: ArithmeticException)

Source code (ArithmeticExceptionExample.java)
/**
 * Example of ArithmeticException in java.
 * @author javaQuery
 * @date 2021-09-07
 * @Github: https://github.com/javaquery/Examples
 */
public class ArithmeticExceptionExample {

    public static void main(String[] args) {
        int x = 10;
        int y = getY();
        System.out.println(x / y);
    }

    /**
     * This is example of getting value from some method call.
     * There is possibilities of getting value `0`.
     *
     * Java compiler can't identify such errors
     */
    public static int getY(){
        return 2-2;
    }
}


BiChannelGoogleApi: [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzaq

Firebase + Google
BiChannelGoogleApi: [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzaq
One weird exception where Google doesn't show whats wrong with our code or process. I faced same exception and I scratched my head all day long to fix this issue and finally I fixed it. I'm using phone based Authentication of Firebase.

Step 1: Enable Firebase logging to see behind whats happening behind the scene. Add following code in your Main activity class where you are performing authentication.
FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
firebaseDatabase.setLogLevel(Logger.Level.DEBUG);
  
Step 2: Now you will get the actual error why its not working. In my case I got following exception.
com.example W/System.err: com.google.firebase.auth.FirebaseAuthException: This app is not authorized to use Firebase Authentication. Please verify that the correct package name and SHA-1 are configured in the Firebase Console. [ App validation failed ]
com.example W/System.err:     at com.google.firebase.auth.api.internal.zzeh.zza(com.google.firebase:firebase-auth@@19.3.1:37)
com.example W/System.err:     at com.google.firebase.auth.api.internal.zzfj.zza(com.google.firebase:firebase-auth@@19.3.1:3)
com.example W/System.err:     at com.google.firebase.auth.api.internal.zzfm.run(com.google.firebase:firebase-auth@@19.3.1:4)
com.example W/System.err:     at android.os.Handler.handleCallback(Handler.java:883)
com.example W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:100)
com.example W/System.err:     at android.os.Looper.loop(Looper.java:214)
com.example W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:7682)
com.example W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
com.example W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
com.example W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
com.example E/"TAG": onComplete: Failed=This app is not authorized to use Firebase Authentication. Please verify that the correct package name and SHA-1 are configured in the Firebase Console. [ App validation failed ]
  
Step 3: I synced Firebase configuration in Android Studio again by Tools > Firebase > Authentication > Connect > Sync

That's it my exception is no longer there. 

How to create immutable class in Java?

immutable class

Immutable Object
Once created its state can not be altered.
String is good example of Immutable class in Java which you use in your day-to-day programming.

Read: Why String is immutable in Java?

Most important benefit of immutable class is, It provides thread safety so you don't have to worry about its value getting changed in multi-threaded environment. Also immutable class with valid hashCode() and equals() method is good choice for Map key.

Points to be taken care while creating immutable class.

  • Class must be declared as final so it can not be extended. i.e public final class ClassName.
  • All variables/critical methods should be private so it can not be accessed outside of class. i.e private int x;.
  • Make all mutable variables final so it can not be changed after initialization.
    i.e private final int x;.
  • Initialize all variables via constructor only by performing deep copy. (follow example)
  • Do not provide setter methods for variables. i.e public void setX(int x) {this.x = x;}
  • Return cloned object/variable in getter method rather returning actual object. (follow example)

Source code (ImmutableClassLatLon.java)
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Example of Immutable class in java.
 * @author javaQuery
 * @date 2019-12-10
 * @Github: https://github.com/javaquery/Examples
 */
public final class ImmutableClassLatLon {
    private final double latitude;
    private final double longitude;
    private final List<String> labels;

    /**
     * @param latitude
     * @param longitude
     * @param labels
     */
    public ImmutableClassLatLon(double latitude, double longitude, List<String> labels) {
        this.latitude = latitude;
        this.longitude = longitude;
        if(labels != null && !labels.isEmpty()){
            this.labels = new ArrayList<>(labels);
        }else{
            this.labels = null;
        }
    }

    /**
     * Will return new copy of List rather returning reference to current list.
     * @return
     */
    public List<String> getLabels() {
        return labels != null ? new ArrayList<>(labels) : null;
    }

    /**
     * Get new object of ImmutableClassLatLon with updated label.
     * @param label
     * @return ImmutableClassLatLon
     */
    public ImmutableClassLatLon addLabel(String label){
        List<String> temporary = new ArrayList<>();
        if(labels != null && !labels.isEmpty()){
            temporary.addAll(labels);
        }
        temporary.add(label);
        return new ImmutableClassLatLon(latitude, longitude, temporary);
    }

    public static void main(String[] args) {
        ImmutableClassLatLon classLatLon = new ImmutableClassLatLon(23.0225, 72.5714, Arrays.asList("India"));
        System.out.println("classLatLon address: " + classLatLon);

        System.out.println("\n- classLatLon getLabels and add label -");
        System.out.println("classLatLon labels before: " + classLatLon.getLabels());
        /* classLatLon.getLabels() will return new copy of List rather returning reference to current list */
        List<String> localLables = classLatLon.getLabels();
        localLables.add("Hindi");
        System.out.println("localLables: " + localLables);
        System.out.println("classLatLon labels after: " + classLatLon.getLabels());

        System.out.println("\n- add new label to classLatLon -");
        System.out.println("classLatLon add label before: " + classLatLon.getLabels());
        /* When new label is added it will return new object of ImmutableClassLatLon rather updating current object's list */
        ImmutableClassLatLon classLatLonNewLabel = classLatLon.addLabel("Asia");
        System.out.println("classLatLon add label after: " + classLatLon.getLabels());
        System.out.println("classLatLonNewLabel address: " + classLatLonNewLabel);
        System.out.println("classLatLonNewLabel labels: " + classLatLonNewLabel.getLabels());

    }
}
Output
As you can see after initialization of ImmutableClassLatLon@36baf30c, user can not change its state even if we provided operation on it.
classLatLon address: com.javaquery.core.immutable.ImmutableClassLatLon@36baf30c

- classLatLon getLabels and add label -
classLatLon labels before: [India]
localLables: [India, Hindi]
classLatLon labels after: [India]

- add new label to classLatLon -
classLatLon add label before: [India]
classLatLon add label after: [India]
classLatLonNewLabel address: com.javaquery.core.immutable.ImmutableClassLatLon@7a81197d
classLatLonNewLabel labels: [India, Asia]
Further Reading
What is the difference between final and effectively final?
How HashMap works internally in Java?
How LinkedHashMap works internally in Java?

How LinkedHashMap works internally in Java?

LinkedHashMap implemented using the HashMap. So before we begin to understand How LinkedHashMap works you should first read How HashMap works internally in Java?

We will understand part of code that defers from HashMap and supports LinkedHashMap implementation.

LinkedHasMap#Entry
Entry class in LinkedHashMap extends Node class of HashMap and contains two more variable before and after to hold the before and after references of Entry object.
static class Entry<K,V> extends HashMap.Node<K,V> {
    Entry<K,V> before, after;
    Entry(int hash, K key, V value, Node<K,V> next) {
        super(hash, key, value, next);
    }
}
Now when you put(key, value) pair in LinkedHashMap, it creates new node object by calling newNode(..) method. In newNode(..) method linkNodeLast(LinkedHashMap.Entry<K,V> p) method is called which is responsible for pointing head and tail element in LinkedHashMap and also set reference of before and after objects.
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
    LinkedHashMap.Entry<K,V> p = new LinkedHashMap.Entry<K,V>(hash, key, value, e);
    linkNodeLast(p);
    return p;
}

private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
    LinkedHashMap.Entry<K,V> last = tail;
    tail = p;
    if (last == null)
        head = p;
    else {
        p.before = last;
        last.after = p;
    }
}
Following image shows graphical representation of How LinkedHashMap works internally.


Lets understand LinkedHashMap implementation using real Java Program to make everything clear.

Source code (LinkedHashMapExample.java)
Note: Check value of before, after and next to understand example.
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * LinkedHashMap Example.
 * @author javaQuery
 * @date 2019-11-29
 * @Github: https://github.com/javaquery/Examples
 */
public class LinkedHashMapExample {
    public static void main(String[] args) {
        Map<String, String> map = new LinkedHashMap<>();

        /* Check value of before, after and next to understand example */
        map.put("AaAaAa", "JJJ");
        /**
         * Current bucket data visualization
         *
         * bucket-index: 2
         * EntryObject1 [before = null, hash = 123, key = AaAaAa, value = JJJ, next = null, after = null]
         */

        map.put("xyz", "KKK");
        /**
         * Current bucket data visualization
         *
         * bucket-index: 2
         * EntryObject1 [before = null, hash = 123, key = AaAaAa, value = JJJ, next = null, after = EntryObject2]
         *
         * bucket-index: 11
         * EntryObject2 [before = EntryObject1, hash = 456, key = xyz, value = KKK, next = null, after = null]
         */

        /* since hashcode of 'AaAaBB' is same as 'AaAaAa' so it be added at 2nd index in bucket */
        map.put("AaAaBB", "LLL");
        /**
         * Current bucket data visualization
         *
         * bucket-index: 2
         * [
         *  EntryObject1 [before = null, hash = 123, key = AaAaAa, value = JJJ, next = EntryObject3, after = EntryObject2]
         *  EntryObject3 [before = EntryObject2, hash = 123, key = AaAaBB, value = LLL, next = null, after = null]
         * ]
         *
         * bucket-index: 11
         * EntryObject2 [before = EntryObject1, hash = 456, key = xyz, value = KKK, next = null, after = EntryObject3]
         */
    }
}
Above program can be graphically represented as follows.


References
How HashMap works internally in Java?
Popular Map interview questions in Java