#Embedded Audit was working with spring boot 1.4 but now not working after upgrade to spring boot 2.1.x - spring

public interface EAuditable {
public static interface Update{
public EUpdateInfo getUpdateInfo();
public void setUpdateInfo(EUpdateInfo updateInfo);
}
public static interface Create{
public ECreateInfo getCreateInfo();
public void setCreateInfo(ECreateInfo createInfo);
}
public static interface UpdateDate{
public ZonedDateTime getLastUpdatedOn();
public void setLastUpdatedOn(ZonedDateTime date);
}
public static interface UpdateUser{
public String getLastUpdatedBy();
public void setLastUpdatedBy(String user);
}
public static interface CreateDate{
public ZonedDateTime getCreatedOn();
public void setCreatedOn(ZonedDateTime date);
}
public static interface CreateUser{
public String getCreatedBy();
public void setCreatedBy(String user);
}
}
#Entity
#Table(name = "TRACKABLE_ITEM")
#Inheritance(strategy = InheritanceType.JOINED)
public class ETrackableItem extends AbstractIdTenantPersistable implements EAuditable.Create, EAuditable.Update {
#Embedded
private ECreateInfo createInfo;
#Embedded
private EUpdateInfo updateInfo;
}
#MappedSuperclass
//JPA: For Eclipse Link, use #AdditionaliCritera instead of #Filter and #FilterDef
#FilterDef(name="multiTenant", parameters=#ParamDef( name="tenant_id", type="string" ) )
#Filter(name="multiTenant", condition=":tenant_id = TENANT_ID")
public abstract class AbstractIdTenantPersistable extends AbstractIdPersistable {
#Column(name = "TENANT_ID", length = 12)
protected String tenantId;
public String getTenantId() {
return tenantId;
}
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
protected AbstractIdTenantPersistable(){}
protected AbstractIdTenantPersistable(UUID id) {
super(id);
}
protected AbstractIdTenantPersistable(UUID id, String tenantId) {
super(id);
this.tenantId = tenantId;
}
}
#MappedSuperclass
#EntityListeners(value = { PersistableEntityListener.class })
#TypeDef(name = "json", typeClass = JsonUserType.class)
public abstract class AbstractPersistable {
public enum ConstraintType{UniqueName, Unique, Others};
/**
* Returns the constraint name to its type mapping.
* #param name
* #return
*/
public ConstraintType getConstraintType(String name){
return ConstraintType.Others;
}
}
public class PersistableEntityListener {
#PrePersist
public void prePersist(AbstractPersistable e) {
if (e instanceof EAuditable.Create){
EAuditable.Create create = (EAuditable.Create) e;
create.setCreateInfo(new ECreateInfo(ZonedDateTime.now(ZoneId.of("UTC")), getUserName()));
}
if (e instanceof EAuditable.CreateDate){
EAuditable.CreateDate createDate = (EAuditable.CreateDate) e;
createDate.setCreatedOn(ZonedDateTime.now(ZoneId.of("UTC")));
}
if (e instanceof EAuditable.CreateUser){
EAuditable.CreateUser createUser = (EAuditable.CreateUser) e;
createUser.setCreatedBy(getUserName());
}
if (e instanceof AbstractIdTenantPersistable){
((AbstractIdTenantPersistable)e).setTenantId(getTenantId());
}
preUpdate(e);
}
#PreUpdate
public void preUpdate(AbstractPersistable e) {
if (e instanceof EAuditable.Update){
EAuditable.Update update = (EAuditable.Update) e;
update.setUpdateInfo(new EUpdateInfo(ZonedDateTime.now(ZoneId.of("UTC")), getUserName()));
}
if (e instanceof EAuditable.UpdateDate){
EAuditable.UpdateDate updateDate = (EAuditable.UpdateDate) e;
updateDate.setLastUpdatedOn(ZonedDateTime.now(ZoneId.of("UTC")));
}
if (e instanceof EAuditable.UpdateUser){
EAuditable.UpdateUser updateUser = (EAuditable.UpdateUser) e;
updateUser.setLastUpdatedBy(getUserName());
}
}
private String getUserName() {
//checkContext();
if (isUserSet()){
return ContextHolder.get().getAuthenticatedContext().getUserName();
}
return "-";
}
private String getTenantId() {
//checkContext();
if (isTenantSet()){
return ContextHolder.get().getAuthenticatedContext().getTenantId();
}
return "-";
}
private boolean isUserSet(){
return ContextHolder.get() != null &&
ContextHolder.get().getAuthenticatedContext() != null &&
ContextHolder.get().getAuthenticatedContext().getUserName() != null;
}
private boolean isTenantSet(){
return ContextHolder.get() != null &&
ContextHolder.get().getAuthenticatedContext() != null &&
ContextHolder.get().getAuthenticatedContext().getTenantId() != null;
}
private boolean isContextSet(){
return isUserSet() && isTenantSet();
}
private void checkContext(){
BeanHolder.asserts().isTrue(
isContextSet(),`enter code here`
DomainException.class, "DOMAIN.CONTEXT_NOT_SET");
}
}
Below the code which was working fine for auto populate the audit info with the spring-data-jpa used with spring boot 1.4.x but it is not working when we upgraded to spring boot 2.1.x
Can any one please help if we have different way of handing for the same.
I need to follow this kind of #Embedded way of doing as here we are doing it by composition except inheritance.
Thanks in advance.

Related

How to register hibernate custom multiple EventListeners

My scenario is need yo track entity property changes. I have used Hibernate PostUpdateEventListener interface to achieve that.
Following is my generic event listener class.
public abstract class EventListener<DOMAIN extends BaseModel> implements PostUpdateEventListener {
public abstract LogSupport getService();
public abstract BaseModel getLogDomain(DOMAIN domain);
#SuppressWarnings("unchecked")
private DOMAIN getDomain(BaseModel model) {
return (DOMAIN) model;
}
public void postUpdate(PostUpdateEvent event, BaseModel model) {
getService().createUpdateLog(getDomain(model), getPostUpdateEventNotes(event));
}
private String getPostUpdateEventNotes(PostUpdateEvent event) {
StringBuilder sb = new StringBuilder();
for (int p : event.getDirtyProperties()) {
sb.append("\t");
sb.append(event.getPersister().getEntityMetamodel().getProperties()[p].getName());
sb.append(" (Old value: ")
.append(event.getOldState()[p])
.append(", New value: ")
.append(event.getState()[p])
.append(")\n");
}
System.out.println(sb.toString());
return sb.toString();
}
}
And this is my custom entity listener.
#Component
public class AssetEventListener extends EventListener<Asset> {
private static final long serialVersionUID = -6076678526514705909L;
#Autowired
#Qualifier("assetLogService")
private LogSupport logSupport;
#Override
public LogSupport getService() {
AutowireHelper.autowire(this, logSupport);
return logSupport;
}
#PostPersist
public void onPostInsert(PostInsertEvent event) {
if (event.getEntity() instanceof BaseModel){
super.postPersist( event, (BaseModel) event.getEntity() );
}
}
#Override
public void onPostUpdate(PostUpdateEvent event) {
if (event.getEntity() instanceof BaseModel){
super.postUpdate( event, (BaseModel) event.getEntity() );
}
}
#Override
public BaseModel getLogDomain(Asset domain) {
return domain;
}
#Override
public boolean requiresPostCommitHanding(EntityPersister persister) {
return false;
}
}
And I called it from #EntityListeners
#Entity
#Table(name = "tbl_asset")
#EntityListeners({ AssetEventListener.class })
public class Asset extends BaseModel {
}
Listener not call when update the entity. Any help would be greatly appreciated.
Thanks,

org.hibernate.exception.DataException: could not execute query in spring boot and Data JPA

When I am trying to implement the JPQL query, I am getting the following error,
{
"message": "could not execute query; SQL [select alerts0_.nalert_id as nalert_i1_0_, alerts0_.bis_active as bis_acti2_0_, alerts0_.dalert_date as dalert_d3_0_, alerts0_.ndept_to as ndept_to4_0_, alerts0_.ninst_to as ninst_to5_0_, alerts0_.nreceiver_id as nreceive6_0_, alerts0_.nsender_id as nsender_7_0_, alerts0_.nsubdept_to as nsubdept8_0_, alerts0_.salert_action_data as salert_a9_0_, alerts0_.salert_desc as salert_10_0_, alerts0_.salert_subject as salert_11_0_, alerts0_.salert_type as salert_12_0_ from alerts alerts0_ where alerts0_.ninst_to=?]; nested exception is org.hibernate.exception.DataException: could not execute query",
"error": "Internal Server Error",
"path": "/spacestudy/rockefeller/control/alerts/getAlertDetails"
}
And my repository query is like the following,
#Query("SELECT a FROM Alerts a")
public List<Alerts> findByAlertType();
When I hard-coded Query like #Query("SELECT a FROM Alerts a WHERE a.nreceiverId = 649"), then also getting the same error.
And I am calling this query in my service like the following:
alert= alertsRepositoryObj.findByAlertType();
And my model class Alerts.java like the following:
#Entity
#Table(name="alerts")
public class Alerts implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY, generator = "alerts_seq_generator")
#SequenceGenerator(name = "alerts_seq_generator", sequenceName = "alerts_seq",allocationSize=1)
#Column(name="nalert_id",columnDefinition="serial")
public Integer nalertId;
#Column(name="salert_desc")
public String salertDesc;
#NotNull
#Column(name="nsender_id")
public Integer nsenderId;
#Column(name="dalert_date")
public LocalDate dalertDate;
#Column(name="salert_subject")
public String salertSubject;
#Column(name="salert_action_data")
public String salertActionData;
#Column(name="salert_type")
public String salertType;
#Column(name="ninst_to")
public Integer ninstTo;
#Column(name="ndept_to")
public Integer nDeptTo;
#Column(name="nsubdept_to")
public Integer nsubdeptTo;
#Column(name="nreceiver_id")
public Integer nreceiverId;
#NotNull
#Column(name="bis_active")
public Boolean bisActive=true;
#ManyToOne(optional = true)
#JoinColumn(name = "salert_action_data", insertable = false, updatable = false)
public RoomTransfer roomTransfer;
public Integer getNalertId()
{
return nalertId;
}
public void setNalertId(Integer nalertId)
{
this.nalertId = nalertId;
}
public String getSalertDesc()
{
return salertDesc;
}
public void setSalertDesc(String salertDesc)
{
this.salertDesc = salertDesc;
}
public Integer getNsenderId()
{
return nsenderId;
}
public void setNsenderId(Integer nsenderId)
{
this.nsenderId = nsenderId;
}
public LocalDate getDalertDate()
{
return dalertDate;
}
public void setDalertDate(LocalDate dalertDate)
{
this.dalertDate = dalertDate;
}
public String getSalertSubject()
{
return salertSubject;
}
public void setSalertSubject(String salertSubject)
{
this.salertSubject = salertSubject;
}
public String getSalertActionData()
{
return salertActionData;
}
public void setSalertActionData(String salertActionData)
{
this.salertActionData = salertActionData;
}
public String getSalertType()
{
return salertType;
}
public void setSalertType(String salertType)
{
this.salertType = salertType;
}
public Integer getNinstTo()
{
return ninstTo;
}
public void setNinstTo(Integer ninstTo)
{
this.ninstTo = ninstTo;
}
public Integer getnDeptTo()
{
return nDeptTo;
}
public void setnDeptTo(Integer nDeptTo)
{
this.nDeptTo = nDeptTo;
}
public Integer getNsubdeptTo()
{
return nsubdeptTo;
}
public void setNsubdeptTo(Integer nsubdeptTo)
{
this.nsubdeptTo = nsubdeptTo;
}
public Integer getNreceiverId()
{
return nreceiverId;
}
public void setNreceiverId(Integer nreceiverId)
{
this.nreceiverId = nreceiverId;
}
public Boolean getBisActive()
{
return bisActive;
}
public void setBisActive(Boolean bisActive)
{
this.bisActive = bisActive;
}
public RoomTransfer getRoomTransfer()
{
return roomTransfer;
}
public void setRoomTransfer(RoomTransfer roomTransfer)
{
this.roomTransfer = roomTransfer;
}
public Alerts()
{
super();
}
}
Why this error happening? Since this is a simple JPQL query. How can I trouble shoot the exact error here?

I am using Spring Jpa Repository to perform all database operations. I don't know how to select a specific value from my table without using any query

My entity class is here:
public class ClientDetails {
public ClientDetails() {
super();
// TODO Auto-generated constructor stub
}
#Id
#GeneratedValue
#Column(name="serialno")
public int serialno;
#Column(name="gstnum")
public int GSTnum;
#Column(name="bunk_name")
public String bunk_name;
#Column(name="mobile_num")
public int mobile_num;
#Column(name="password")
public String password;
public int getSerialno() {
return serialno;
}
public void setSerialno(int serialno) {
this.serialno = serialno;
}
public int getGSTnum() {
return GSTnum;
}
public void setGSTnum(int gSTnum) {
GSTnum = gSTnum;
}
public String getBunk_name() {
return bunk_name;
}
public void setBunk_name(String bunk_name) {
this.bunk_name = bunk_name;
}
public int getMobile_num() {
return mobile_num;
}
public void setMobile_num(int mobile_num) {
this.mobile_num = mobile_num;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
I want to select gstnum from my table based on my bunk_name.I don't want any native query like i did for gstnum in my jpa repository.
SELECT gstnum from pbm.client_details where bunk_name = 'yoga';
MY JPA REPOSITORY is
public interface ClientDetailsRepository extends JpaRepository<ClientDetails,Integer> {
public static final String gst_num = "SELECT * FROM pbm.client_details;";
//public static final String login_access = "SELECT * FROM clien_details WHERE gstnum pbm.client_details;";
#Query(value = gst_num, nativeQuery = true)
List<ClientDetails> getGstnum();
}
You could use the #Query but Spring Data would result not having too
#Query("SELECT GSTnum FROM ClientDetails where bunk_name = :callMeSomething")
List<ClientDetails> getGstnum(#Param("callMeSomething") String callMeSomething);
How a look here JPA Docs

Axon Event Handler not Working

I am developing a small cqrs implementation and I am very new to it.
I want to segregate each handlers(Command and Event) from aggregate and
make sure all are working well. The command handler are getting triggered
from controller but from there event handlers are not triggered. Could
anyone Please help on this.
public class User extends AbstractAnnotatedAggregateRoot<String> {
/**
*
*/
private static final long serialVersionUID = 1L;
#AggregateIdentifier
private String userId;
private String userName;
private String age;
public User() {
}
public User(String userid) {
this.userId=userid;
}
#Override
public String getIdentifier() {
return this.userId;
}
public void createuserEvent(UserCommand command){
apply(new UserEvent(command.getUserId()));
}
#EventSourcingHandler
public void applyAccountCreation(UserEvent event) {
this.userId = event.getUserId();
}
}
public class UserCommand {
private final String userId;
public UserCommand(String userid) {
this.userId = userid;
}
public String getUserId() {
return userId;
}
}
#Component
public class UserCommandHandler {
#CommandHandler
public void userCreateCommand(UserCommand command) {
User user = new User(command.getUserId());
user.createuserEvent(command);
}
}
public class UserEvent {
private final String userId;
public UserEvent(String userid) {
this.userId = userid;
}
public String getUserId() {
return userId;
}
}
#Component
public class UserEventHandler {
#EventHandler
public void createUser(UserEvent userEvent) {
System.out.println("Event triggered");
}
}
#Configuration
#AnnotationDriven
public class AppConfiguration {
#Bean
public SimpleCommandBus commandBus() {
SimpleCommandBus simpleCommandBus = new SimpleCommandBus();
return simpleCommandBus;
}
#Bean
public Cluster normalCluster() {
SimpleCluster simpleCluster = new SimpleCluster("simpleCluster");
return simpleCluster;
}
#Bean
public ClusterSelector clusterSelector() {
Map<String, Cluster> clusterMap = new HashMap<>();
clusterMap.put("com.user.event.handler", normalCluster());
//clusterMap.put("exploringaxon.replay", replayCluster());
return new ClassNamePrefixClusterSelector(clusterMap);
}
#Bean
public EventBus clusteringEventBus() {
ClusteringEventBus clusteringEventBus = new ClusteringEventBus(clusterSelector(), terminal());
return clusteringEventBus;
}
#Bean
public EventBusTerminal terminal() {
return new EventBusTerminal() {
#Override
public void publish(EventMessage... events) {
normalCluster().publish(events);
}
#Override
public void onClusterCreated(Cluster cluster) {
}
};
}
#Bean
public DefaultCommandGateway commandGateway() {
return new DefaultCommandGateway(commandBus());
}
#Bean
public Repository<User> eventSourcingRepository() {
EventStore eventStore = new FileSystemEventStore(new SimpleEventFileResolver(new File("D://sevents.txt")));
EventSourcingRepository eventSourcingRepository = new EventSourcingRepository(User.class, eventStore);
eventSourcingRepository.setEventBus(clusteringEventBus());
AnnotationEventListenerAdapter.subscribe(new UserEventHandler(), clusteringEventBus());
return eventSourcingRepository;
}
}
As far as I can tell, the only thing missing is that you aren't adding the User Aggregate to a Repository. By adding it to the Repository, the User is persisted (either by storing the generated events, in the case of Event Sourcing, or its state otherwise) and all Events generated by the Command Handler (including the Aggregate) are published to the Event Bus.
Note that the Aggregate's #EventSourcingHandlers are invoked immediately, but any external #EventHandlers are only invoked after the command handler has been executed.

Spring Data Jpa Test returns null list even after child is saved

#Test
public void testAddPlayerToGame() {
gameRepository.save(createTestGame());
Game game = gameRepository.findOne(1l);
assertTrue(game.getId() > 0);
Player p = new Player();
p.setName("test 1");
p.setGame(game);
p.setChips(5000);
assertTrue(p.getId() == null);
playerRepository.saveAndFlush(p);
assertTrue(p.getId() != null);
flushAndClear();
Game game2 = gameRepository.findOne(1l);
assertEquals(1, game2.getPlayers().size());
}
The above test fails because game2.getPlayers() returns null.
Already went through JpaRepository caches newly created object. How to refresh it? but couldn't figure out how to solve.
The method flushAndClear used in the above code is blank, as follows :
protected void flushAndClear() {
// sessionFactory.getCurrentSession().flush();
// sessionFactory.getCurrentSession().clear();
}
Any help is really appreciated.
Update
Game & Player mapping code :
#Entity
#Table(name="game")
public class Game implements Serializable {
private static final long serialVersionUID = -495064662454346171L;
private long id;
private int playersRemaining;
private Player playerInBTN;
private GameType gameType;
private String name;
private boolean isStarted;
private Set<Player> players;
private HandEntity currentHand;
private GameStructure gameStructure;
#Column(name="game_id")
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Column(name="players_left")
public int getPlayersRemaining() {
return playersRemaining;
}
public void setPlayersRemaining(int playersRemaining) {
this.playersRemaining = playersRemaining;
}
#OneToOne
#JoinColumn(name="btn_player_id")
public Player getPlayerInBTN(){
return playerInBTN;
}
public void setPlayerInBTN(Player playerInBTN){
this.playerInBTN = playerInBTN;
}
#Column(name="game_type")
#Enumerated(EnumType.STRING)
public GameType getGameType() {
return gameType;
}
public void setGameType(GameType gameType) {
this.gameType = gameType;
}
#OneToMany(mappedBy="game", fetch=FetchType.LAZY)
public Set<Player> getPlayers() {
return players;
}
public void setPlayers(Set<Player> players) {
this.players = players;
}
#Column(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Column(name="is_started")
public boolean isStarted() {
return isStarted;
}
public void setStarted(boolean isStarted) {
this.isStarted = isStarted;
}
#OneToOne(fetch=FetchType.EAGER)
#JoinColumn(name="current_hand_id")
public HandEntity getCurrentHand() {
return currentHand;
}
public void setCurrentHand(HandEntity currentHand) {
this.currentHand = currentHand;
}
#OneToOne(fetch=FetchType.EAGER, cascade={CascadeType.ALL})
#JoinColumn(name="game_structure_id")
public GameStructure getGameStructure() {
return gameStructure;
}
public void setGameStructure(GameStructure gameStructure) {
this.gameStructure = gameStructure;
}
}
#Entity
#Table(name="player")
public class Player implements Comparable<Player>, Serializable{
private static final long serialVersionUID = -1384636077333014255L;
private String id;
private Game game;
private String name;
private int chips;
private int gamePosition;
private int finishPosition;
private boolean sittingOut;
#JsonIgnore
#Column(name="player_id")
#Id
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid2")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#JsonIgnore
#ManyToOne
#JoinColumn(name="game_id")
public Game getGame() {
return game;
}
public void setGame(Game game) {
this.game = game;
}
#Column(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Column(name="chips")
public int getChips() {
return chips;
}
public void setChips(int chips) {
this.chips = chips;
}
#Column(name="game_position")
public int getGamePosition() {
return gamePosition;
}
public void setGamePosition(int gamePosition) {
this.gamePosition = gamePosition;
}
#Column(name="finished_place")
public int getFinishPosition() {
return finishPosition;
}
public void setFinishPosition(int finishPosition) {
this.finishPosition = finishPosition;
}
#Column(name="sitting_out")
public boolean isSittingOut() {
return sittingOut;
}
public void setSittingOut(boolean sittingOut) {
this.sittingOut = sittingOut;
}
#Override
public boolean equals(Object o){
if(o == null || !(o instanceof Player)){
return false;
}
Player p = (Player) o;
if(this.getId() == null){
return this.getName().equals(p.getName());
}
return this.getId().equals(p.getId());
}
#Override
public int hashCode(){
if(id == null){
return name.hashCode();
}
return id.hashCode();
}
#Override
#Transient
public int compareTo(Player p){
return this.getGamePosition() - p.getGamePosition();
}
}
I am using HSQL db in the testing environment. Following is the configuration :
#Configuration
#EnableJpaRepositories(basePackages = "com.nitinsurana.repos")
#EnableTransactionManagement
class TestDataConfig {
#Bean(name = "transactionManager")
#Autowired
public PlatformTransactionManager getTransactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
return jpaTransactionManager;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("com.nitinsurana.domain");
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
em.setJpaProperties(getHibernateProperties());
em.afterPropertiesSet();
return em.getObject();
}
// #Bean
// public EntityManager entityManager(HibernateEntityManagerFactory entityManagerFactory) {
// HibernateEntityManager entityManager = (HibernateEntityManager) entityManagerFactory.createEntityManager();
// entityManager.setFlushMode(FlushModeType.AUTO FlushMode.ALWAYS);
// return entityManager;
// }
private Properties getHibernateProperties() {
Properties prop = new Properties();
prop.put("hibernate.show_sql", "false");
prop.put("hibernate.hbm2ddl.auto", "create");
prop.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
return prop;
}
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
// .addScript("classpath:com/bank/config/sql/schema.sql")
// .addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
}
You need to write a FlushAndClear method that works. If not game2 gets not loaded for the database but from the internal cache. And if it is not loaded then the releationship become not updated.
class TestXXX {
#PersistenceContext
private EntityManager em.
private flushAndClear() {
em.flush();
em.clear();
}
}

Resources