I want to interceptor to the data fetch from database using hibernate that if in my data, particular field is present then get the value and check if that value is applicable to the user who queried it.
My application uses spring mvc with hibernate. I have configured an interceptor at session factory level.
class AuditInterceptor extends EmptyInterceptor {
#Override
public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
System.out.println("******************************* instantiated ****************************");
return null;
}
#Override
public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
System.out.println("******************************* on load ****************************");
return true;
}
}
In my spring-dao.xml
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="c3p0DataSource" />
<property name="packagesToScan">
...
</property>
<property name="hibernateProperties">
....
</property>
<property name="entityInterceptor">
<bean class="com.hibernate.AuditInterceptor" />
</property>
</bean>
I want whenever query.list() excutes it should be able to intercept data using above inteceptor.
Now, it is calling my interceptor when my application starts. I am not able to get data for validation.(I want to perform validation in interceptor)
Related
I simply want to change the date format in my DTO returned by #ResponseBody
My question is not this question as my output is a JSON List and I am printing it on Postman instead of using a view with JS and other UI features.
It's not this one as well because I am returning a JSON List, not just the Date object.It is an extension of this one, but I don't think Orika mapper is the culprit.
I am getting the timestamp value of date on returning the List using #ResponseBody.
My custom code-
#RequestMapping(value = "/my/report", method = RequestMethod.POST)
#ResponseBody
public List<OrderWsDTO> createReport() {
//stuff
return Optional.ofNullable(orderDataList)
.orElse(Collections.emptyList())
.stream()
.map(orderData -> getDataMapper().map(orderData, OrderWsDTO.class, fields))
.collect(Collectors.toList());
}
The mapper is:
map:162, ConfigurableMapper (ma.glasnost.orika.impl)
Same issue with getDataMapper().mapAsList(orderDataList, OrderWsDTO.class, fields):
#RequestMapping(value = "/my/report", method = RequestMethod.POST)
#ResponseBody
public List<OrderWsDTO> createReport() {
//stuff
return getDataMapper().mapAsList(orderDataList, OrderWsDTO.class, fields);
}
OrderWsDTO is a DTO with getters and setters and a date field that is java.util.Date.
In postman I can see the date format as : "date": "1552476861991"
The same exact call which returns OrderWsDTO instead of List<OrderWsDTO> changes the date format. It is printing the date as 2019-03-13T12:10:05+0000 which is format : yyy-MM-dd'T'HH:mm:ss.SSXXX
#RequestMapping(value = "/my/report", method = RequestMethod.POST)
#ResponseBody
public OrderWsDTO createReport() {
//stuff
return getDataMapper().map(orderData, OrderWsDTO.class, fields);
}
Why is the date showing two different formats when printed in List<DTO> and DTO?
Also, where is it getting the format : yyy-MM-dd'T'HH:mm:ss.SSXXX?
Edit 1:
The date is getting formatted here:
de.hybris.platform.webservicescommons.jaxb.adapters.DateAdapter#marshal()Format : yyyy-MM-dd'T'HH:mm:ssZ
Now, how to override this class?
Edit 2:
I am not able to override the jaxbContextFactory which has the list of adapters to modify the date. The jaxbContextFactory looks like-
<alias name="defaultJaxbContextFactory" alias="jaxbContextFactory"/>
<bean id="defaultJaxbContextFactory" class="de.hybris.platform.webservicescommons.jaxb.MoxyJaxbContextFactoryImpl">
<property name="wrapCollections" value="${webservicescommons.messageconverters.context.wrapCollections}" />
<property name="analysisDepth" value="${webservicescommons.messageconverters.context.analysisDepth}" />
<property name="typeAdapters" ref="jaxbTypeAdaptersList" />
<property name="subclassRegistry" ref="subclassRegistry" />
<property name="otherClasses" ref="jaxbContextClasses" />
<property name="metadataSourceFactory" ref="metadataSourceFactory" />
<property name="excludeClasses" ref ="jaxbContextFactoryExcludeClasses"/>
</bean>
On overriding this bean in my custom code it is still picking the old values for typeAdapters. Interestingly, it is replacing other properties with my custom properties.
My custom overridden bean-
<alias name="defaultJaxbContextFactory" alias="jaxbContextFactory"/>
<bean id="defaultJaxbContextFactory" class="de.hybris.platform.webservicescommons.jaxb.MoxyJaxbContextFactoryImpl">
<property name="wrapCollections" value="false" />
<property name="analysisDepth" value="30" />
<property name="typeAdapters" ref="mylist" />
<property name="subclassRegistry" ref="subclassRegistry" />
<property name="otherClasses" ref="jaxbContextClasses" />
<property name="metadataSourceFactory" ref="metadataSourceFactory" />
<property name="excludeClasses" ref ="jaxbContextFactoryExcludeClasses"/>
</bean>
<util:list id="mylist">
<value>com.myproject.mymodule.myadapter</value>
<value>de.hybris.platform.webservicescommons.jaxb.adapters.VariableMapAdapter</value>
<value>de.hybris.platform.webservicescommons.jaxb.adapters.XSSStringAdapter</value>
</util:list>
For typeAdapters it is always picking the values-
<property name="typeAdapters">
<list>
<value>de.hybris.platform.webservicescommons.jaxb.adapters.DateAdapter</value>
<value>de.hybris.platform.webservicescommons.jaxb.adapters.StringMapAdapter</value>
<value>de.hybris.platform.webservicescommons.jaxb.adapters.XSSStringAdapter</value>
</list>
</property>
Edit 3:
I tried overriding the bean in mycustomaddon-web-spring.xml as -
<bean id="customJaxbContextFactory" parent="jaxbContextFactory">
<property name="metadataSourceFactory" ref="customMetadataSourceFactory" />
<property name="typeAdapters">
<list>
<value>myproject.adapters.DateAdapter</value>
<value>de.hybris.platform.webservicescommons.jaxb.adapters.StringMapAdapter</value>
<value>de.hybris.platform.webservicescommons.jaxb.adapters.XSSStringAdapter</value>
</list>
</property>
</bean>
I have added the custom adapter class i.e. myproject.adapters.DateAdapter in acceleratoraddon/web.
Did not work out though.
The 'jaxbContextFactory' bean is first defined in the 'webservicescommons-spring.xml' which creates the bean in the application context. So when you override the bean in your custom extension using (customExtension)-spring.xml, it is just overriding the bean in the application context. More information about context loading in Hybris can be found here.
The typeAdapters property mentioned in your comments is defined in another bean which is defined in the 'jaxb-converters-spring.xml'
<bean id="customJaxbContextFactory" parent="jaxbContextFactory">
<property name="metadataSourceFactory" ref="customMetadataSourceFactory" />
<property name="typeAdapters">
<list>
<value>de.hybris.platform.webservicescommons.jaxb.adapters.DateAdapter</value>
<value>de.hybris.platform.webservicescommons.jaxb.adapters.StringMapAdapter</value>
<value>de.hybris.platform.webservicescommons.jaxb.adapters.XSSStringAdapter</value>
</list>
</property>
</bean>
Since the beans defined in the jaxb-converters-spring-xml are loaded in the WebApplicationContext, you will need to override this bean using the (customExtension)-web-spring.xml where you can define the bean and corresponding class in the websrc of your custom extension.
I have a service class annotated with #Transactional calling a DAO layer method to return an object with a collection on it lazily loaded. When I then try and initialize this collection in the service layer using Hibernate.inititialize(..), hibernate doesn't load the collection. The DAO is configured to use entity manager and the object class is annotated with JPA annotations. I have the following spring application context..
<beans xmlns="http://www.springframework.org/schema/beans"...">
<orcl:pooling-datasource id="dataSource" url="..." username="..." password="..."/>
<context:annotation-config/>
<!-- Hibernate entity manager -->
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="org.gmp.webapp.model" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="dao" class="org.gmp.webapp.dao.impl.HibDAOImpl" />
</beans>
My DAO interface and implementaionn...
package org.gmp.webapp.dao;
import java.util.List;
import org.gmp.webapp.model.Crime;
public interface DAO {
public Crime getCrime(String crimeNo);
}
import org.gmp.webapp.dao.DAO;
import org.gmp.webapp.model.Crime;
public class HibDAOImpl implements DAO {
#PersistenceContext
protected EntityManager em;
public Crime getCrime(String crimeNo) {
return this.em.find(Crime.class, crimeNo);
}
}
My object looks something like this..
#Entity
#Table(name="CRIME_TABLE")
public class Crime {
#Id
#Column(name = "CRIME_NO")
private String crimeNo;
#OneToMany
#JoinColumn(name="PER_CRIME_NO", referencedColumnName="CRIME_NO")
private List<PersonCrimeLink> personLinks;
....
public List<PersonCrimeLink> getPersonLinks() {
return personLinks;
}
}
The service class is annotated with transactional (spring) so I thought as the call to the DAO and the initialize were in the same transaction, this should work.
My service..
#Service
#Transactional(readOnly=true)
public class CrimeServiceImpl implements CrimeService {
#Autowired private CrimeDAO crimeDAO;
public Crime getCrime(String crimeNo) {
Crime crime = crimeDAO.getCrime(crimeNo);
Hibernate.initialize(crime.getPersonLinks());
return crime;
}
}
The collection is loaded when I run a test of the DAO method, when making a call to the getter for the collection. I have annotated the test method with #Transactional. The personLinks object is omitted but like I say it returns the records in the test. I think I am not understanding the transaction manager I am using as this process worked when I was using session factory and HibernateTransactionManager.
Many Thanks in advance for any guidance on this.
Just a quick tip on this, as you decided to use the JPA's EntityManagerFactory instead of the Hibernate's SessionFactory as your orm API, then i would stick to that API on other layers of the application.
That is, using the EntityManager to get the data and then switch to using the implementation API (Hibernate.initialize) is not a consistent / maintainable approach.
Like you said in the post, if you stick to the JPA specification, which is initializing collection once it is accessed for the first time then you do not get any errors and the list is loaded:
The LAZY strategy is a hint to the persistence provider runtime that
data should be fetched lazily when it is first accessed
So as of JPA specification, you only need to do this:
public Crime getCrime(String crimeNo) {
Crime crime = crimeDAO.getCrime(crimeNo);
crime.getPersonLinks().size(); // any access method
return crime;
}
In the Spring docs, for NEVER propagation:
Execute non-transactionally, throw an exception if a transaction
exists.
I wanted to try like following:
#Transactional(propagation = Propagation.NEVER)
public void getDeps(long ID) {
System.out.println(databaseImp.getDepartmentByID(ID));
}
#Transactional(propagation = Propagation.REQUIRED)
public void allProcessOnDB_second(long ID) {
getDeps(ID);
operation(ID);
}
#Transactional
public void operation(long id){
System.out.println(databaseImp.getDepartmentByID(id));
}
Well, it is not important what code wants to do.
I use the #Transactional(propagation = Propagation.NEVER) and I use this method in any transactional method but it doesn't work. I mean it must throw an exception, but it doesn't.
My Spring meta configuration file (XML) contains the following:
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="database.transactionmanagement"/>
<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg name="dataSource" ref="datasource2"/>
</bean>
<bean id="datasource2" class="org.apache.tomcat.dbcp.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/hr"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
Thanks for your answers.
#Transactional annotations only apply to the Spring proxy objects. For example, if you call allProcessOnDB_second() from some spring bean which injects your service like this
#Autowired
private MyService myService;
...
myService.allProcessOnDB_second();
then myService is Spring proxy, and its #Transactional(propagation = Propagation.REQUIRED) is applied. If you were to call myService.getDeps(id) then #Transactional(propagation = Propagation.NEVER) would be applied.
But when you call the first method, and then second method from it, then second method isn't called through Spring proxy but rather directly, so its transactional configuration is ignored.
Spring transactions are proxy-based. That exception would be thrown if a bean A called another bean B, because the transactional aspect would intercept the call and throw the exception. But here, you're calling another method in the same object, and the transactional proxy is thus out of the picture.
I am trying to implement the following: clear some details from DB on SpringSecurity logout handler. The main problem that after trying to get user details from DB I get this error. The rest of code and even the same method work fine in other cases.
public class CurrentUserLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
/**
*
*/
#Autowired
private RequestsService requestsService;
/**
*
*/
#Autowired
private OffersService offersService;
/**
*
*/
#Autowired
private UsersService usersService;
/**
*
*/
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
if (authentication != null) {
UserDetailsExtended details = (UserDetailsExtended) authentication.getPrincipal();
User user = usersService.get(details.getId()); // fails here
requestsService.unlockAllByBackoffice(user);
offersService.unlockAllByBackoffice(user);
}
setDefaultTargetUrl("/");
super.onLogoutSuccess(request, response, authentication);
}
}
Config:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.ejl.butler.object.data" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
<prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
DAO:
public User get(final Long id) {
Session session = SessionFactoryUtils.getSession(sessionFactory, false);
return (User) session.get(User.class, id);
}
Spring security config:
<logout invalidate-session="true" logout-url="/logout" success-handler-ref="logoutSuccessHandler"/>
Exception:
No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
at org.springframework.orm.hibernate3.SessionFactoryUtils.doGetSession(SessionFactoryUtils.java:356)
at org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(SessionFactoryUtils.java:202)
#Transactional resolves the problem but I can't understand why? I mean it fails only in this handler in all other calls this method works fine without this annotation!
Thank you in advance!
UPD:
My temporary solution is to add #Transactional to whole onLogoutSuccess method.. It works)
If you have defined a TransactionManager in your spring context you have to specify #Transactional somewhere in the stack. Otherwise you will get the exception you encountered because you are trying to run a query outside of a transaction.
There are workarounds to this such specifying current_session_context_class in your hibernate configuration to thread or
<property name="current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</property>
but it's not production safe..
The possible values for current_session_context_class are jta, thread and managed. Further to that, jta and thread are supported by hibernate out of box. thread context is used in most stand alone hibernate apps or those based on light weight frameworks like Spring and jta is used in Java EE environments.
Also try sessionFactory.getCurrentSession() instead of SessionFactoryUtils.getSession().
I use spring 3.0.5 and with hibernate.
Interceptor is working.
Send domain id to jms queue.
Consumer recive it and search domain, but is faster than database commit and i get null.
How to be shure that interceptor will be called after db commit ?
appCtx.xml
<tx:annotation-driven order="10" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<aop:aspectj-autoproxy />
<bean id="domainProducerHandler" depends-on="domainEventService"
class="org.test.service.DomainProducerHandler" factory-method="aspectOf">
<property name="domainEventService" ref="domainEventService" />
<property name="order" value="1" />
</bean>
===================service class=====================
#SendDomainEvent
#Transactional
public ProtoMessage sendDonation(String aa) {
Domain domainObj = new Domain();
domainRepository.saveAndFlush(domainObj);
return domain;
}
==================interceptor class===================**
#AfterReturning(
pointcut="#annotation(org.test.service.SendDomainEvent)",
returning="retVal")
public void processDomainReturn(Object retVal) {
....
try {
domainEventService.publishToQueue(endDonationSuccessEvent);
} catch (Exception e) {
log.error("error during send endDonationSuccessEvent: " + e);
}
}
Interceptor class implements Ordered interface. I set order parameter to tx:annotation-driven order="10" but it doesn't work.
What do you mean by "order parameter"? The supported ways of ordering advice in Spring AOP are with the #Ordered annotation or the org.springframework.core.Ordered interface, which also defines constants for the highest and lowest priorities.