'Java EE FirebaseApp name [DEFAULT] already exists

I got a problem related to Firebase and Java EE.

I'm currently writing some Java servlets for my project and I'm using Firebase the first time because I wanted to try something new.

My actual problem is the following: I got a servlet which is responsible for exchanging an iOS device token in an user database. This is necessary for sending Remote Push Notifications to a device. I've done this like in the google tutorials, but I'm getting the following exception:

java.lang.IllegalStateException: FirebaseApp name [DEFAULT] already exists!

The way I'm accessing the Firebase Database is through the Java SDK.

I do this with the following code:

connect method

    // gets called by the servlet to configure Firebase
    public static void connect() {
      try {
        // for authentication purpose
        Map<String, Object> auth = new HashMap<>();
        auth.put("uid", "my-service-account");

        // Setting up the FirebaseOptions object
        // constant FIREBASE_DATABASE_URL = "url to my database"
        // constant FIREBASE_KEY_PATH = "path to my json key"
        options = new FirebaseOptions.Builder()
                  .setDatabaseUrl(FIREBASE_DATABASE_URL)
                  .setServiceAccount(new FileInputStream(FIREBASE_KEY_PATH))
                  .setDatabaseAuthVariableOverride(auth)
                  .build();

        FirebaseApp.initializeApp(options);

        // calling the method for exchanging the token
        exchangeIosDeviceToken("[email protected]", "5bf53173c9ef0a37638f3ddaa59cf2c0687c14ca0dcd47ccf57f9f09bd6368ab");
      } catch (FileNotFoundException ex) {
        ex.printStackTrace();
      }
    }

exchangeIosDeviceToken method

    public static boolean exchangeIosDeviceToken(String email, String newDeviceToken) {
      FirebaseDatabase database = FirebaseDatabase.getInstance();

      // getting a reference to my "employee" child
      DatabaseReference employeeReference = database.getReference("/employee");

      Map<String, Object> employeeUpdates = new HashMap<>();
      // updating the device token with child "iosDeviceToken" of "employee"
      employeeUpdates.put(email+"/iosDeviceToken", newDeviceToken);

      // update the actual children
      employeeReference.updateChildren(employeeUpdates);
      return true;
    }

The funny part is when I'm trying to execute this code in a standalone main class (replacing the connect method, with the main method), the code is working.

Before you're saying things like "there are tons of questions related to this topic"... They are nearly all related to Android and questions related to my problem seldom got answered.

Regards



Solution 1:[1]

Solved the problem.

The problem was: I've called the connect method everytime a request was incoming.

Solution: Call the connect method only once. (ServletContextListener)

Solution 2:[2]

this for the future users, You can check whether the default app is initialized or not like this.

    FirebaseApp firebaseApp = null;
    List<FirebaseApp> firebaseApps = FirebaseApp.getApps();
    if(firebaseApps!=null && !firebaseApps.isEmpty()){
        for(FirebaseApp app : firebaseApps){
            if(app.getName().equals(FirebaseApp.DEFAULT_APP_NAME))
                firebaseApp = app;
        }
    }
    else
        firebaseApp = FirebaseApp.initializeApp(options);   

Solution 3:[3]

This exception appear because you are trying to create the [DEFAULT] FirebaseApp again, simply you can add a validation to check if it exist or not before the initialization, like this:

if(FirebaseApp.getInstance(FirebaseApp.DEFAULT_APP_NAME) != null) {
    return;
}

Solution 4:[4]

My fix to this issue was call FirebaseApp.getInstance().delete();

Solution 5:[5]

My solution

    package com.zs.configuration;

    import com.google.auth.oauth2.GoogleCredentials;
    import com.google.firebase.FirebaseApp;
    import com.google.firebase.FirebaseOpt`enter code here`ions;
    import com.google.firebase.auth.FirebaseAuth;

    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    import java.io.FileInputStream;

    @WebListener
    public class MyAppServletContextListener
            implements ServletContextListener{

        @Override
        public void contextDestroyed(ServletContextEvent arg0) {
            System.out.println("ServletContextListener destroyed");
        }

        //Run this before web application is started
        @Override
        public void contextInitialized(ServletContextEvent arg0) {
            try {
                FileInputStream serviceAccount = new FileInputStream(getClass().getClassLoader().getResource("zs.json").getFile());

                FirebaseOptions options = new FirebaseOptions.Builder()
                        .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                        .setDatabaseUrl("https://zs.firebaseio.com")
                        .build();


                FirebaseApp firebaseApp = FirebaseApp.initializeApp(options);
                FirebaseAuth.getInstance(firebaseApp);

            }catch (Exception exc){
                System.out.println("Firebase exception "+exc);

            }
            System.out.println("ServletContextListener started");
        }
    }

In my Application class

    @ServletComponentScan
    @SpringBootApplication
    public class ZSApplication {


        public static void main(String[] args) {

            SpringApplication.run(ZSApplication.class, args);

        }

    }

Solution 6:[6]

Summarising all the solutions, very good ones BTW, proposed here: Running code after Spring Boot starts please find below the spring-boot (2.6.3) implementations which works for me.

Beware: Substitute with your app and files names below.

Placing the firebase initialisation method ( FirebaseApp.initializeApp(options)) directly on the main method (as I found on this tutorial: https://www.youtube.com/watch?v=8jK9O0lwem0) it caused the error, just because, debugging I notice, for some reason the call of the method FirebaseApp.initializeApp(options); is done multiple times.

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Objects;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;

import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@SpringBootApplication
public class YourAppNameApplication {

    public static void main(String[] args) {
        SpringApplication.run(YourAppNameApplication.class, args);
    }

    /**
     * Initialize the firebase SDK to integrate with the firebase application. Used
     * for check the clients UIDs authentications.
     * 
     * @throws IOException in case the firebase configuration JSON file is not
     *                     present on the path.
     */
    @EventListener(ApplicationReadyEvent.class)
    public void initFirebaseSDK() throws IOException {
        ClassLoader classLoader = YourAppNameApplication.class.getClassLoader();

        File file = new File(
                Objects.requireNonNull(classLoader.getResource("your_file_firebase.json")).getFile());
        FileInputStream serviceAccount = new FileInputStream(file.getAbsolutePath());

        @SuppressWarnings("deprecation")
        FirebaseOptions options = new FirebaseOptions.Builder()
                .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                .setDatabaseUrl("https://your_firebase_app_name.firebaseio.com").build();

        FirebaseApp.initializeApp(options);

        if (!(FirebaseApp.getApps().isEmpty())
                && FirebaseApp.getInstance(FirebaseApp.DEFAULT_APP_NAME).getName() != null) {
            log.info("Firebase SDK has been initialised with the app name: "
                    + FirebaseApp.getInstance(FirebaseApp.DEFAULT_APP_NAME).getName());
        } else {
            log.error(
                    "Firebase SDK has NOT been initialised. This is a serious error. Please contact the administrator of the app.");
        }
    }

}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 schmidi000
Solution 2 Kanishk Gupta
Solution 3 Ebraheem Alrabeea
Solution 4 epool
Solution 5 Lucas Rampoldi
Solution 6 ittradco