3

I'm trying to save data to Firebase using a desktop application written in Java. However, for some reason it doesn't work, I've been folowing the documentation provided here: https://firebase.google.com/docs/database/admin/save-data. Couldn't find any video tutorials on the matter, all videos are web or mobile related. Basically I want to create an object called Venda that has 3 attributes (ID, data, valor) and then save it on Firebase. Thank you!

Here is the main method:

public class Main {

    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println("--------- Begin of Output ---------");
        Firebase firebase = new Firebase();
        VendasCRUD venda = new VendasCRUD(firebase);
        venda.createVenda(new Venda(0, "23/05/1993", 45.67));
        System.out.println("----------- End of Output -----------");
    }

}

Firebase connection:

public class Firebase {

    public Firebase() throws FileNotFoundException, IOException {
        FileInputStream serviceAccount = new FileInputStream("C:\\Users\\Alex\\Documents\\NetBeansProjects\\SEMS\\src\\main\\java\\br\\com\\sems\\firebase\\sems-firebase.json");

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

        FirebaseApp.initializeApp(options);
    }

    public DatabaseReference getDataBaseReference() {
        return FirebaseDatabase.getInstance().getReference();
    }

}

Venda class:

public class Venda {

    public int ID;
    public String data;
    public double valor;

    public Venda(int ID, String data, double valor) {
        this.ID = ID;
        this.data = data;
        this.valor = valor;
    }

    @Override
    public String toString() {
        return ID + "," + data + "," + valor;
    }

}

The database info:

enter image description here

For now the rules are set to public, for testing purposes.


UPDATE:

Alright after trying what was proposed on FrankvanPuffelen's comment I'm still not able to save or read data from Firebase. I made a simpler code for testing purposes. Here is the code:

public class Main {

    private static final String DATABASE_URL = "https://sems-firebase.firebaseio.com/";
    private static DatabaseReference database;
    private static boolean finished = false;

    public static void startListeners() {
        database.child("posts").addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                Post post = dataSnapshot.getValue(Post.class);
                System.out.println(post);
                finished = true;
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                System.out.println("The read failed: " + databaseError.getCode());
            }
        });
        while(!finished);
    }

    public static void main(String[] args) throws FileNotFoundException {

        try {
            FileInputStream serviceAccount = new FileInputStream("sems-firebase.json");
            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                    .setDatabaseUrl(DATABASE_URL)
                    .build();



        FirebaseApp defaultApp =  FirebaseApp.initializeApp(options);
        FirebaseDatabase defaultDatabase = FirebaseDatabase.getInstance(defaultApp);

        System.out.println(defaultDatabase.getReference().toString());

    } catch (IOException e) {
        System.out.println("ERROR: invalid service account credentials. See README.");
        System.out.println(e.getMessage());

        System.exit(1);
    }

    // Shared Database reference
    database = FirebaseDatabase.getInstance().getReference();

    // Start listening to the Database
    startListeners();

}

}

So what I've been doing is, I run the code and then go to the database url and manually edit a post, I expect to get a print of the post I just edited on the console, but nothing happens.

Here is a snapshot of the database: enter image description here


UPDATE 2

I believe what was proposed here: Why Firebase Java SDK can't terminate after set? is deprecated, because if I try the code looks like this:

enter image description here

I tried modifying that to this:

public static void startListeners() throws InterruptedException {
    DatabaseReference database = FirebaseDatabase.getInstance().getReference("posts/adad2131/author");
    CountDownLatch done = new CountDownLatch(1);
    database.setValue("Test", new DatabaseReference.CompletionListener() {
        @Override
        public void onComplete(DatabaseError de, DatabaseReference dr) {
            done.countDown();
        }
    });
    done.await();
}

But the onComplete method never gets executed and the programs never finishes. As for what was proposed here: java Firebase: delay exit until writes finish may also be deprecated as it seems the CompletionListener() no longer lives inside Firebase, but I could find it inside DatabaseReference, so I modified the code to this:

private static final String DATABASE_URL = "https://sems-firebase.firebaseio.com/";

public static void startListeners() throws InterruptedException {
    DatabaseReference database = FirebaseDatabase.getInstance().getReference("posts/adad2131/author");
    final AtomicBoolean done = new AtomicBoolean(false);
    database.setValue("Test", new DatabaseReference.CompletionListener() {
        @Override
        public void onComplete(DatabaseError de, DatabaseReference dr) {
            done.set(true);
        }
    });
    while (!done.get());
}

Like before, the onComplete method never gets executed and the program never finishes or set the data in the database. Here is a snapshot of the post I'm trying to modify:

enter image description here


UPDATE 3

So I've simplified the code for ease of use. Just to be sure I generated a new private key from the project's service account pannel, here is how I initialize the app:

    try {
        FileInputStream serviceAccount = new FileInputStream("sems-firebase-firebase-adminsdk-gamnp-874087bbd1.json");
        FirebaseOptions options = new FirebaseOptions.Builder()
                .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                .setDatabaseUrl("https://sems-firebase.firebaseio.com/")
                .build();

        FirebaseApp.initializeApp(options);

    } catch (IOException e) {
        System.out.println("ERROR: invalid service account credentials.");
        System.out.println(e.getMessage());

        System.exit(1);
    }

Here is a snapshot of the database, the value I'm trying to change is the author field of post with id "adad2131".

enter image description here

I've tried referencing that field with "posts/adad2131/author", "/posts/adad2131/author" or simply "adad2131/author", maybe I'm referencing it wrong?

Here is the full code:

public class Main {

    public static void main(String[] args) throws FileNotFoundException, InterruptedException {

        try {
            FileInputStream serviceAccount = new FileInputStream("sems-firebase-firebase-adminsdk-gamnp-874087bbd1.json");
            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                    .setDatabaseUrl("https://sems-firebase.firebaseio.com/")
                    .build();

            FirebaseApp.initializeApp(options);

        } catch (IOException e) {
            System.out.println("ERROR: invalid service account credentials.");
            System.out.println(e.getMessage());

            System.exit(1);
        }

        //Try to change data in Firebase
        CountDownLatch done = new CountDownLatch(1);
        FirebaseDatabase.getInstance().getReference("posts/adad2131/author").setValue("Test", new DatabaseReference.CompletionListener() {
            @Override
            public void onComplete(DatabaseError de, DatabaseReference dr) {
                done.countDown();
            }
        });
        done.await();

    }
}

Ps. I'm also using admin sdk 5.9

Alexandre Krabbe
  • 727
  • 1
  • 13
  • 33
  • 1
    Most likely your Java program exits before Firebase was able to write the data. The typical solutions are to add a delay (very simple) or use a semaphore to signal when the writing is done (way better). Let me find a question that has some samples already. – Frank van Puffelen Apr 08 '18 at 22:53
  • 1
    Examples: https://stackoverflow.com/questions/45253891/why-firebase-java-sdk-cant-terminate-after-set, https://stackoverflow.com/questions/26092632/java-firebase-delay-exit-until-writes-finish, https://groups.google.com/forum/#!searchin/firebase-talk/exit$20java/firebase-talk/BHa8M9YE1RE/aW4dwn_pZ88J – Frank van Puffelen Apr 08 '18 at 22:56
  • As soon as I get home I’ll take a look at the link you posted and give a feedback, thank you. – Alexandre Krabbe Apr 08 '18 at 22:58
  • So I've read the answers and tried both solutions proposed. The first one did make the program stop, but it never set the data or finished the program. For the second one it uses Firebase.CompletionListener() from com.firebase.client.Firebase; however, for some reason maven can't find that dependency. The third link I couldn't open, do you think there is something wrong with the way I'm trying to inserto into de database? – Alexandre Krabbe Apr 09 '18 at 01:16
  • I found the CompletionListener() inside DatabaseReference instead of Firebase, but it still didn't write to the database. I'm starting to wonder if there is something wrong with my database reference. – Alexandre Krabbe Apr 09 '18 at 01:38
  • @FrankvanPuffelen – Alexandre Krabbe Apr 09 '18 at 18:20
  • Without seeing your updated code, it's hard to see what's going on. – Frank van Puffelen Apr 09 '18 at 19:47
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/168600/discussion-between-alexandre-krabbe-and-frank-van-puffelen). – Alexandre Krabbe Apr 10 '18 at 00:14
  • @FrankvanPuffelen I added the updated code, can you help me? I really need to get this working. Thank you for your help so far. – Alexandre Krabbe Apr 10 '18 at 00:16
  • You're doing a [tight loop](https://stackoverflow.com/questions/2212973/what-is-a-tight-loop), which is quite different from what the links I provided do. I really can't make it much shorter than what I showed here: https://stackoverflow.com/a/45256059 or what Kato showed here: https://stackoverflow.com/a/26112036. – Frank van Puffelen Apr 10 '18 at 00:44
  • @FrankvanPuffelen thank you for your input so far, in fact I had tried what was suggested in those posts, but since it didn't work I decided not to post my code for that. But as of now I added a UPDATE 2 section with the code for both of those tries. – Alexandre Krabbe Apr 10 '18 at 01:12

1 Answers1

3

I just copied your code into a project using Firebase Admin SDK 5.9 and ran it, and it wrote to the database without problems.

CountDownLatch done = new CountDownLatch(1);
FirebaseDatabase.getInstance().getReference("49723347").setValue("Test", new DatabaseReference.CompletionListener() {
    @Override
    public void onComplete(DatabaseError de, DatabaseReference dr) {
        done.countDown();
    }
});
done.await();

You can see the result here: https://stackoverflow.firebaseio.com/49723347.json

The reference 49723347 is the path in my database (it's the ID of your question). I made no other changes.

So it seems that the problem is not in the code we've been looking at. Here's how I initialize the app:

FileInputStream serviceAccount = new FileInputStream("stackoverflow-3d9889aaeddb.json");

FirebaseOptions options = new FirebaseOptions.Builder()
        .setCredential(FirebaseCredentials.fromCertificate(serviceAccount))
        .setDatabaseUrl("https://stackoverflow.firebaseio.com/")
        .build();

FirebaseApp.initializeApp(options);

Are you sure the configuration is for the project you're trying to write?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • My only clue is that I might be referencing the author field wrong, I added a UPDATE 3 section showing what I have done. – Alexandre Krabbe Apr 10 '18 at 02:50
  • Looks basically the same to me. Are you sure you're getting to your `setValue` call? If you run in a debugger and set a breakpoint on that line, does it get triggered? – Frank van Puffelen Apr 10 '18 at 02:53
  • I did just that, the breakpoint on the setValue() line does get triggered, then it executes the done.await() and never finishes because the onComplete() never gets triggered. I tried also setting a breakpoint on the onComplete() and here is the output `Listening on 55920 User program running Not able to submit breakpoint LineBreakpoint Main.java : 38, reason: No executable location available at line 38 in class br.com.firebasetest.Main$1. Invalid LineBreakpoint Main.java : 38` – Alexandre Krabbe Apr 10 '18 at 02:59
  • Are there any extra configurations that needs to be done in the project itself? – Alexandre Krabbe Apr 10 '18 at 03:00
  • Do you think it has to do with the fact that there is no app configured in the Firebase dashboard? I had used the realtime database before for a iOS app and didn’t have any problems. But there are only options to setup web, android and iOS applications there, no option for a java desktop app. Do you want to try setting data directly into my database? I can give you the json private key, its just a test database anyway. – Alexandre Krabbe Apr 10 '18 at 16:23
  • I just checked and I don't have an app for my Admin project either. So I doubt that makes a difference. – Frank van Puffelen Apr 10 '18 at 16:58
  • Do you think I should contact Firebase support in order to solve this problem? They say their support does not cover code, so if I need support on code I should post on Stackoverfkow. Since I did just that and my program still doesn’t work, that’s my last resort. – Alexandre Krabbe Apr 10 '18 at 17:28
  • I highly doubt your project is in a borked state, so support likely will do the same I've been doing: trying to get to an [MCVE](http://stackoverflow.com/help/mcve). Then again: maybe someone there sees something that we've both been missing. Be sure to point out this thread when you open a case, because my tests have shown that the specific code fragment is not the problem. This might also be a good moment to trim your question: the problem shouldn't need more code than what I have used. Since you see a different behavior than what I see with that code, the code seems fine. – Frank van Puffelen Apr 10 '18 at 17:45
  • Alright, I’ll open a ticket later following your instructions. Thank you so much for your time and patience so far. As soon as I have an answer I will post here. – Alexandre Krabbe Apr 10 '18 at 17:55
  • Frank, on the [docs](https://firebase.google.com/docs/admin/setup?hl=pt-br) it states that "The Firebase Admin Java SDK is published to the Maven central repository. To install the library, declare it as a dependency in your build.gradle file" `dependencies { compile 'com.google.firebase:firebase-admin:5.9.0' }` I never did that, I only added ` com.google.firebase firebase-admin 5.9.0 ` to my pom.xml file. Also I tried changing a value in a database the I know works, so the problem isn't on DB – Alexandre Krabbe Apr 10 '18 at 21:57
  • So I think this narrows it down to some configuration in my local machine, any ideas? – Alexandre Krabbe Apr 10 '18 at 21:59