Jabref: Exception when "pulling changes" from local database

Created on 29 Sep 2020  路  10Comments  路  Source: JabRef/jabref

JabRef 5.2--2020-09-29--2d92025
Linux 4.12.14-lp151.28.67-default amd64
Java 15

Steps to reproduce the behavior:

  1. Load a local database.
  2. Click on "Pull changes from shared database"
  3. Exception has been thrown.


Log File

java.lang.NullPointerException: Cannot invoke "org.jabref.logic.shared.DatabaseSynchronizer.pullChanges()" because "<local1>" is null at org.jabref.gui.shared.PullChangesFromSharedAction.lambda$execute$0(Unknown Source) ~[org.jabref:?] at java.util.Optional.ifPresent(Unknown Source) ~[?:?] at org.jabref.gui.shared.PullChangesFromSharedAction.execute(Unknown Source) ~[org.jabref:?] at org.jabref.gui.actions.JabRefAction.lambda$new$2(Unknown Source) ~[org.jabref:?] at org.controlsfx.control.action.Action.handle(Unknown Source) ~[org.jabref.merged.module:?] at org.controlsfx.control.action.Action.handle(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source) ~[org.jabref.merged.module:?] at javafx.event.Event.fireEvent(Unknown Source) ~[org.jabref.merged.module:?] at javafx.scene.control.MenuItem.fire(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.scene.control.ContextMenuContent$MenuItemContainer.doSelect(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.scene.control.ContextMenuContent$MenuItemContainer.lambda$createChildren$12(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source) ~[org.jabref.merged.module:?] at javafx.event.Event.fireEvent(Unknown Source) ~[org.jabref.merged.module:?] at javafx.scene.Scene$MouseHandler.process(Unknown Source) ~[org.jabref.merged.module:?] at javafx.scene.Scene.processMouseEvent(Unknown Source) ~[org.jabref.merged.module:?] at javafx.scene.Scene$ScenePeerListener.mouseEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source) ~[org.jabref.merged.module:?] at java.security.AccessController.doPrivileged(Unknown Source) ~[?:?] at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.glass.ui.View.handleMouseEvent(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.glass.ui.View.notifyMouse(Unknown Source) ~[org.jabref.merged.module:?] at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method) ~[org.jabref.merged.module:?] at com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(Unknown Source) ~[org.jabref.merged.module:?] at java.lang.Thread.run(Unknown Source) [?:?]

good first issue shared-database bug 馃悰

All 10 comments

The solution would be to create another BooleanExpression in the ActionHelper class, e..g needsSharedDatabase
filter there
And in the action you can then bind it, e..g:
this.executable.bind(ActionHelper.needsEntriesSelected(stateManager));

Hi! Can I work on this?

Sure. Go ahead, if you have any questions ask here or in our gitter channel

Hello I'm back. I think I have a solution almost worked out but I need a little help.

I added the binding in PullChangesFromSharedAction.java

    public PullChangesFromSharedAction(StateManager stateManager) {
        this.stateManager = stateManager;

        this.executable.bind(ActionHelper.needsDatabase(stateManager));
        this.executable.bind(ActionHelper.needsSharedDatabase(stateManager)); //new
    }

The problem is I'm still not sure how to make the validation in the ActionHelper.java. So far my approach is something like this:

    public static BooleanExpression needsSharedDatabase(StateManager stateManager){
        return stateManager.activeDatabaseProperty().isEqualTo("shared");
    }

The problem is that in the .isEqualTo I'm not sure with what I should compare it to detect when the user is not using a shared database.

I would really appreciate some help to make my first contribution!

Idea is good so far, for checking if it's a shared database you better check the bibdatabasecontect e.g
databaseContext.getLocation() == DatabaseLocation.SHARED)

Bindings.createBooleanBinding is probably your friend here. Be aware that you can combine two Bindings with .and()

Update:

I came up with this solution:

    public static BooleanExpression needsSharedDatabase(StateManager stateManager) {
        BibDatabaseContext databaseContext = stateManager.activeDatabaseProperty().orElse(null).get();
        return Bindings.createBooleanBinding(() -> databaseContext != null && databaseContext.getLocation() == DatabaseLocation.SHARED);
    }

But now the problem is that the validation is only being done at the start when I run the program. I'm guessing It's related to the StateManager.java but I'm fairly new to JavaFX so I'll keep looking into it.

You need to add the check for the active database property in the booleanBinding itself. The Bindings are wrapper around Observables. Observables update whenever their values changes.
Some background info: https://docs.oracle.com/javase/8/javafx/properties-binding-tutorial/binding.htm

I think something like this could work:
you may need to add some null checks

     var binding = Bindings.createBooleanBinding(()->
        stateManager.activeDatabaseProperty().getValue().filter(context->context.getLocation() == DatabaseLocation.SHARED).isPresent(),
        stateManager.activeDatabaseProperty());

        return BooleanExpression.booleanExpression(binding);

Thanks a lot @Siedlerchr I really appreciate your help. I'll look into it.

orElse(null) is always a bad idea...
Try using .isEmpty() inside the lambda expression.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

caugner picture caugner  路  3Comments

lenhard picture lenhard  路  4Comments

tobiasdiez picture tobiasdiez  路  4Comments

thorstenwagner picture thorstenwagner  路  4Comments

Siedlerchr picture Siedlerchr  路  3Comments