Can I define same JPA callback method in parent and child class as below? If yes, do I need to invoke super.onPrePersist(); in child class onPrePersist() method?
#MappedSuperclass
public abstract class AbstractEntity {
#PrePersist
protected onPrePersist() {
System.out.println("Parent onPrePersist() invoked");
}
}
#Entity
#Table(name = "child")
public class Child extends AbstractEntity {
#PrePersist
protected onPrePersist() {
**super.onPrePersist();**
System.out.println("Child onPrePersist() invoked");
}
}
I have written a unit test for the above scenario and It works. For each of the callback methods in child class, you have to invoke the parent callback method first:
#Override
#PrePersist
protected onPrePersist() {
**super.onPrePersist();**
System.out.println("Child onPrePersist() invoked");
}
You don't have to invoke the parent callback method by yourself, just don't override the #PrePersist annotated method as it hides the parent method and prevents it from being executed. If your callback methods have different names they will be invoked in the order according to their place in the hierarchy, most general classes first.
#MappedSuperclass
public abstract class AbstractEntity {
#PrePersist
protected onPrePersistParent() {
System.out.println("Parent onPrePersist() invoked");
}
}
#Entity
#Table(name = "child")
public class Child extends AbstractEntity {
#PrePersist
protected onPrePersistChild() {
System.out.println("Child onPrePersist() invoked");
}
}
This will produce the output:
Parent onPrePersist() invoked
Child onPrePersist() invoked
Related
I have created simple project with dagger2 and mvp.
This is my component :
#MainScope
#Component(modules = {MainModule.class})
public interface IMainComponent {
void inject(MainActivity mainActivity);
}
and This is MainModule.class:
#Module
public class MainModule {
#MainScope
#Provides
IMain.IMainModel model() {
return new MainModel();
}
}
Now in presenter i want to inject presenter from it's constructor so i do :
public class MainPresenter implements IMain.IMainPresenter {
IMain.IMainModel model;
IMain.IMainView view;
#Inject
public MainPresenter(IMain.IMainModel model) {
this.model = model;
}
But i got This error:
symbol: class DaggerIMainComponent
location: package com.safarayaneh.engineer.main.di
E:\Projects\Android\NewEng\Engineer\engineer\src\main\java\com\safarayaneh\engineer\main\di\IMainComponent.java:9: error: [Dagger/MissingBinding] com.safarayaneh.engineer.main.mvp.IMain.IMainPresenter cannot be provided without an #Provides-annotated method.
When make provider in MainModule.class to create presenter and remove #Inject above presenter constructor , everything is fine:
#Module
public class MainModule {
#MainScope
#Provides
IMain.IMainModel model() {
return new MainModel();
}
#MainScope
#Provides
IMain.IMainPresenter presenter(IMain.IMainModel model) {
return new MainPresenter(model);
}
}
Your problem is that your Activity expects IMain.IMainPresenter, but if you just annotate the constructor then what's placed on the objects graph is the concrete MainPresenter.
You've got three options here:
Use explicit provider method (as you did)
Use #Binds annotation inside the module to specify that MainPresenter should be provided as IMain.IMainPresenter
Don't use interface for the presenter
Is it by any means possible to #Inject a Service-Bean (say a session bean) into an entity Listener?
Consider the following scenario as an example
Entity:
#Entity
#EntityListeners(BookListener.class)
public class Book {
// fields, getters & setters
}
Utility class:
#Singleton
public class BookUtil {
private BookRepository bookRepo;
private List<Book> bookList;
#Inject
public BookUtil(BookRepository bookRepo){
this.bookRepo = bookRepo;
this.bookList = this.bookRepo.findAll();
}
public void refreshBooks(){
this.bookList = this.bookRepo.findAll();
}
}
Listener:
public class BookListener {
#Inject
BookUtil bookUtil // --> CAN THIS BE ACHIEVED?
#PostPersist
private void refreshCache(Book b){
bookUtil.refreshBooks();
}
}
I tried out several things I could think of but none of them successfully injected an instance of BookUtil. I could manually instantiate it, which works. But I prefer injection as then the BookRepository(inside the BookUtil) would also be injected, without me having to worry about it
dataNucleus 5.1.1: dnSetid NoSuchMethodError
#MappedSuperclass
public class Foo {
#Transient
public Long getId() {
...
}
public void setId(Long id) {
...
}
}
#Entity
public class Bar extends Foo {
#Id
#GeneratedValue(strategy=GenerationType.TABLE, generator="gen")
#TableGenerator(name="gen", ...)
public Long getId() {
...
}
}
java.lang.NoSuchMethodError: No virtual method dnSetid(Long) in class com.example.Bar
at com.example.Bar.dnCopyKeyFieldsFromObjectId(Unknown Source:15)
at com.example.Bar.dnNewInstance(Unknown Source:10)
at org.datanucleus.enhancer.EnhancementHelper.newInstance(EnhancementHelper.java:178)
at org.datanucleus.state.StateManagerImpl.initialiseForHollow(StateManagerImpl.java:373)
at org.datanucleus.state.ObjectProviderFactoryImpl.newForHollow(ObjectProviderFactoryImpl.java:113)
at org.datanucleus.ExecutionContextImpl.findObject(ExecutionContextImpl.java:3194)
at org.datanucleus.store.rdbms.query.PersistentClassROF.findObjectWithIdAndLoadFields(PersistentClassROF.java:458)
at org.datanucleus.store.rdbms.query.PersistentClassROF.getObject(PersistentClassROF.java:364)
at org.datanucleus.store.rdbms.query.ForwardQueryResult.nextResultSetElement(ForwardQueryResult.java:180)
at org.datanucleus.store.rdbms.query.ForwardQueryResult$QueryResultIterator.next(ForwardQueryResult.java:408)
at org.datanucleus.store.rdbms.query.ForwardQueryResult.processNumberOfResults(ForwardQueryResult.java:136)
at org.datanucleus.store.rdbms.query.ForwardQueryResult.advanceToEndOfResultSet(ForwardQueryResult.java:164)
at org.datanucleus.store.rdbms.query.ForwardQueryResult.closingConnection(ForwardQueryResult.java:290)
at org.datanucleus.store.query.AbstractQueryResult.disconnect(AbstractQueryResult.java:105)
at org.datanucleus.store.rdbms.query.AbstractRDBMSQueryResult.disconnect(AbstractRDBMSQueryResult.java:251)
at org.datanucleus.store.rdbms.query.JPQLQuery$2.managedConnectionPreClose(JPQLQuery.java:654)
at org.datanucleus.store.rdbms.ConnectionFactoryImpl$ManagedConnectionImpl.close(ConnectionFactoryImpl.java:532)
at org.datanucleus.store.connection.AbstractManagedConnection.release(AbstractManagedConnection.java:83)
at org.datanucleus.store.rdbms.ConnectionFactoryImpl$ManagedConnectionImpl.release(ConnectionFactoryImpl.java:371)
at org.datanucleus.store.rdbms.query.JPQLQuery.performExecute(JPQLQuery.java:730)
at org.datanucleus.store.query.Query.executeQuery(Query.java:1966)
at org.datanucleus.store.query.Query.executeWithMap(Query.java:1873)
dnSetid should be added by enhancement. Decompiled Bar.class: there is no such method. It contains dnGetid() and other methods dn****.
The only way of overriding is to override BOTH getter AND setter.
Likely the enhancer relies on both being there, whether it is for a defined property or an overridden property.
I have a small question to Dagger2.
But first let me show the sample code:
#Singleton
#Component(module={ApplicationModule.class})
public Interface ApplicationComponent {
}
#Module
public class ApplicationModule {
#Provides
public Context provideContext() {
return context;
}
}
I know that the objects from the component now are "Singletons"..
My question... Did that have any effect to the Module? Is the Module also Singleton?
No, the Module will not be singleton unless you specify the scope for the #Provides annotated provider methods as well.
#Singleton
#Component(module={ApplicationModule.class})
public Interface ApplicationComponent {
Context context;
}
#Module
public class ApplicationModule {
#Provides //unscoped, every injection is new instance
public Context context() {
return context;
}
#Provides
#Singleton //scoped, one instance per component
public Something something() {
return new Something();
}
}
Supposing the following code snippet which uses #PrePersist and #PreUpdate annotations and Joined-type inheritance:
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
public abstract class A {
...
#PrePersist
private void prePersist() {
...
}
#PreUpdate
private void preUpdate() {
...
}
}
#Entity
#DiscriminatorValue("B")
public class B extends A {
...
#PrePersist
private void prePersist() {
...
}
#PreUpdate
private void preUpdate() {
...
}
}
Question: Can we rely on any order of execution of the callback methods?
For example when persisting class A and B will the prePersist method in B executed before the prePersist method in A or viceversa?
Can we assume that the prePersist in B will be executed before the class A is persisted?
Yes. First the superclass callbacks will be executed.
When an event is raised, the listeners are executed in this order:
#EntityListeners for a given entity or superclass in the array order
Entity listeners for the superclasses (highest first)
Entity Listeners for the entity
Callbacks of the superclasses (highest first)
Callbacks of the entity
For more details details read about: "Callbacks and listeners inheritance" at
https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/listeners.html
For me the solution was use the annotation
Example:
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import java.time.LocalDateTime;
#Data
#MappedSuperclass
public abstract class AuditObject {
#Column(name = "dat_created")
private LocalDateTime createdAt;
#PrePersist
public void onPrePersist() {
this.createdAt = LocalDateTime.now();
}
}
#Entity
public class Person extends AuditObject {
}