Entity Manager not working in JavaFX

2019-02-21 03:58发布

I'm using Persistence unit and Entity classes from Database, all in a JavaFx fxml Application, I succeeded importing all my tables as entities in my Model, the proble is that I get an exceptions and errors when I try to insert into an entity, here's my entire code

 public class SampleController implements Initializable {
     @PersistenceContext(unitName="RawdaPU")
     private EntityManager em;

     @FXML
     private Label label;

     @FXML
     private void handleButtonAction(ActionEvent event)
     {
         Moyendidactique moyenDidactique = new Moyendidactique("1", "moyen1", "Type1");
         em.persist(moyenDidactique);
         em.close();
     }

     @Override
     public void initialize(URL url, ResourceBundle rb)
     {
         // TODO
     }     
}

Here is the full errors I get when I press the button (when handleButtonAction is fired)

java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1440)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:69)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:38)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:28)
    at javafx.event.Event.fireEvent(Event.java:171)
    at javafx.scene.Node.fireEvent(Node.java:6863)
    at javafx.scene.control.Button.fire(Button.java:179)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:193)
    at com.sun.javafx.scene.control.skin.SkinBase$4.handle(SkinBase.java:336)
    at com.sun.javafx.scene.control.skin.SkinBase$4.handle(SkinBase.java:329)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:64)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:38)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:33)
    at javafx.event.Event.fireEvent(Event.java:171)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3324)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3164)
    at javafx.scene.Scene$MouseHandler.access$1900(Scene.java:3119)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1559)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2261)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:228)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:528)
    at com.sun.glass.ui.View.notifyMouse(View.java:922)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
    at com.sun.glass.ui.win.WinApplication$2$1.run(WinApplication.java:67)
    at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1435)
    ... 41 more
Caused by: java.lang.NullPointerException
    at rawda.Controller.SampleController.handleButtonAction(SampleController.java:37)
    ... 46 more

I couldn't find an answer in the already existing similar questions, Can't know exactly what I'm missing, thanks in advance for helping.

1条回答
冷血范
2楼-- · 2019-02-21 04:30

Why you get a NullPointerException in your code

The @PersistenceContext annotation "Expresses a dependency on a container-managed EntityManager and its associated persistence context."

By default FXML controllers are not container-managed, which means they aren't going to set container-managed members such as those marked with the @PersistenceContext.

You can use FXML controllers in a container-managed environment by defining a controller factory for your FXMLLoader (for example as the InjectionProvider is used to inject values into in the Afterburner.fx framework).

But really, you don't need to do that injection if you are just starting out with Java. The inversion of control stuff likely adds a bit too much magic until you are used to it.

Recommended JavaFX Integration Approach to Try for JPA Beginners

Instead, don't rely on the @PersistenceContext annotation. Get an entity manager directly from an entity manager factory reference. There is a good example of using an EntityManager outside a container managed environment in the java2s sample Create Query From Entity Manager.

In your application provide a mechanism to get an entity manager:

public class SampleApplication extends Application {
  static private EntityManagerFactory emf;
  static {
    try {
      emf = Persistence.createEntityManagerFactory("RawdaPU");
    } catch (Exception e) {
      System.out.println("Fatal: Unable to create entity manager factory");
      e.printStackTrace();
    }  
  }

  static public EntityManager createEntityManager() {
    return emf.createEntityManager();
  }

  @Override 
  public void start(Stage stage) {
    . . .
  }
}

In your controller, get an entity manager from the application and use it as needed.

class SampleController implements Initializable {
  @FXML
  private Label label;

  @FXML 
  private void handleButtonAction(ActionEvent event) {
    EntityManager em = SampleApplication.createEntityManager();
    Moyendidactique moyenDidactique = new Moyendidactique("1", "moyen1", "Type1");
    em.persist(moyenDidactique);
    em.close();
  }

  @Override
  public void initialize(URL location, ResourceBundle resources) {}
}

On Closing and Entity Manager Lifetimes

Because your original example closed the entity manager after the persist statement, I moved the entity manager creation into the same method as the close method so that they are matched. The close means that the entity manager can't be used again, so you may as well create it in the same place that you close it - that way you can't reuse it somewhere else by mistake. Note that you don't need to do the close like that and can reuse the entity manager if you like, but for getting started with jpa, just doing it as in this example answer is likely fine and you can look into more complex entity manager reuse scenarios as you get more experience and confidence with the technology.

Concurrency Concerns

You also need to be aware of concurrency integrations of JPA usage in your application. Doing stuff such as the JPA calls directly in the button's action handler is not usually a great idea because the calls are blocking I/O that will halt the JavaFX application thread and freeze up your application UI for periods of time. Instead, it is best to make use of the JavaFX task and service concurrency utilities to handle JPA interaction similar to how the database work is abstracted from the UI thread in the JavaFX JDBC task sample.

For a small local database it is concurrency is likely not that much of a concern, so you could try your app first single threaded and if it works fine, great, but if it is freezing up then look into the concurrency utilities.

Next Steps

The above approach is really a quick getting started thing.

Once you understand this simple approach, you may want to look into the more structured design demonstrated in the afterburner.fx and airhacks-control frameworks or the (much more heavyweight) javafx/jpa/spring framework integration.

查看更多
登录 后发表回答