I am using declarative transactions in Spring. I have a service layer which is annotated with "Transactional". This service layer calls the DAO. I need to enable a hibernate filter in all the dao methods. I don't want to have to explicitly call teh session.enablefilter each time. So is there a way using spring transaction aop etc such that a intercepter can be called when the hibernate session is created?
My Service layer:
#Service("customerViewService")
#Transactional
public class CustomerViewServiceImpl extends UFActiveSession implements CustomerViewService {
private static final Logger log = LoggerFactory.getLogger(CustomerViewServiceImpl.class);
private CustomerDAO daoInstance = null;
private CustomerDAO getCustomerDAO() {
if (daoInstance == null)
daoInstance = DAOFactory.getDao(CustomerDAO.class);
return daoInstance;
}
#Transactional(propagation=Propagation.REQUIRED, rollbackFor=DAOException.class)
public CustomerModel getCustomerModel() throws UFClientException {
CustomerModel model = null;
try {
Customer customerTbl = getCustomerDAO().getCustomerDetail(getUserName());
if (customerTbl == null) {
log.error("DAO-02: No entry found for Customer id- " + getUserName());
throw new UFClientException("DAO-02");
}
model = DozerConverter.hibernateToDto(customerTbl, CustomerModel.class);
}
catch (DAOException e) {
log.error("DAO-01: Not able to fetch entry from database for customer.");
throw new UFClientException();
}
return model;
}
}
My Dao Layer
public class CustomerDAOImpl extends HibernateDaoSupport implements CustomerDAO {
#SuppressWarnings("unchecked")
public Customer getCustomerDetail(String email) throws DAOException {
try {
List<Customer> customers = getHibernateTemplate().find(sb.toString(), email);
if (customers.size() == 0)
return null;
return customers.get(0);
}
catch (Exception e) {
throw new DAOException(e);
}
}
Appreciate your help!!
You can create your own interceptor, and apply it to methods that havbe transactional:
#AroundInvoke("#annotation(transactional)")
public ... handle(Transactional transactional) {
...
}
Related
I am attempting to read data from an Android Room database in a background Service. There are no exceptions but no data is returned.
I wrote a function to select all rows from a table in the DAO. Calling that function from a background service succeeds, but it returns no data.
My "Contact" class holds contact information (names, phone numbers, emails) and defines the database schema. The database holds rows of contacts, with names, phone numbers, an emails as columns.
The function that returns the LiveData in the DAO is:
#Query("SELECT * FROM contacts_table")
LiveData<List<Contact>> getAll();
where "contacts_table" is the database table holding contact information.
I called getAll as follows:
AppDatabase db = AppDatabase.getDatabase(messageSenderContext.getApplicationContext());
mContactDAO = db.contactDAO();
mAllContacts = mContactDAO.getAll();
where mContactDao is a ContactDAO (The Database Access Object for my Contact class), and mAllContacts is a LiveData>. These are private fields of the class calling getAll().
db.contactDAO() returns an object, as does mContactDAO.getAll(). But attempting to unpack the List from mAllContacts using mAllContacts.getValue() returns null.
This turned out to be a misuse of LiveData. That requires an Observer to actually get the data.
In your ROOM
#Database(entities={Contact.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
public static final String DATABASE_NAME = "AppDatabase.db";
private static volatile AppDatabase INSTANCE;
private static final int NUMBER_OF_THREADS = 4;
public static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
public abstract ContactDAO contactDAO();
public static AppDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (AppDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
AppDatabase.class, DATABASE_NAME)
.build();
}
}
}
return INSTANCE;
}
}
In your DAO
#Dao
public interface ContactDAO{
#Query("SELECT * FROM contacts_table")
LiveData<List<Contact>> getAll();
}
In your repository:
public class AppRepository {
private ContactDAO mContactDAO;
//constructor
public AppRepository(Application application) {
AppDatabase db = AppDatabase.getDatabase(application);
mContactDAO= db.contactDAO();
}
public LiveData<List<Contact>> getAllContacts(){
LiveData<List<Contact>> contactsList = null;
Future<LiveData<List<Contact>>> futureList = AppDatabase.EXECUTOR_SERVICE.submit(new Callable(){
#Override
public LiveData<List<Contact>> call() {
return contactDAO.getAll();
}
});
try {
contactsList = futureList.get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return contactsList ;
}
}
In your ViewModel
public class ContactsViewModel extends AndroidViewModel {
private AppRepository appRepository;
private LiveData<List<Contact>> contactsList;
public ContactsViewModel(#NonNull Application application) {
super(application);
appRepository = new AppRepository(application);
}
public LiveData<List<Contacts>> list() {
return appRepository.getAllContacts();
}
}
In your activity (inside of onCreated put)
ContactsViewModel contactsViewModel = new ViewModelProvider(this).get(ContactsViewModel.class);
contactsViewModel.list().observe(getViewLifecycleOwner(), new Observer<List<Contact>>() {
#Override
public void onChanged(List<Contact> contactsList) {
//the contact list will be observed and will return data if there are changes.
//use for example to feed the adapter of a recyclerview
//below an example just to view the contacts data
for(Contact conctact : contactsList){
Log.d("TestApp>>>", "Id: + contact.getId);
Log.d("TestApp>>>", "Name: + contact.getName);
}
});
I generate a list of instances which implement interface CheckInterface
using reflection, but some of those instances need to use JPA repository
,as they are new by reflection so Spring will not inject repository for them.
So how can I inject repository into these instance
Or how can I delegate these class to spring as #Bean and iterate them?
#Component
#Log4j
public class ValidationRegister {
public static HashMap<String, CheckItem> itemHashMap = new HashMap<>();
static {
if (itemHashMap.size() == 0) {
Reflections reflections = new Reflections(CheckItem.class.getPackage().getName());
Set<Class<? extends CheckItem>> itemClasses =
reflections.getSubTypesOf(CheckItem.class);
for (Class<? extends CheckItem> checkItemClass : itemClasses) {
try {
itemHashMap.put(checkItemClass.getName(), checkItemClass.newInstance());
} catch (Exception e) {
log.error("ValidationRegister fail : ", e);
}
}
}
}
}
public class LPHYCZ extends CheckItem {
#Autowired
ClaimDataEntityRepository claimDataEntityRepository;
#Override
public boolean check(ClaimRequest request, List<String> errorList) {
ClaimDataEntity claimDataEntity = claimDataEntityRepository.findByClaimId(request.getClaimId());
if (claimDataEntity != null) {
return true;
}
return false;
}
}
When I get instance of LPHYCZ from ValidationRegister.itemHashMap its
claimDataEntityRepository will be null
Just make your Reflections reflections a Spring Bean and get it injected into 'ValidationRegister' then use it to initialize your HashMap your hashmap still can be static, if you want it to be shared by multiple ValidationRegister instances, but the injection won't happen on static fields.
Fighting with TestNG, Spring an Hibernate. I'm writing test for Service class, and it's always failure. But without test class works fine. So App is working, but tests don't want to.
Here is my test class
#Transactional
public class BorrowerServiceTest {
#Mock
BorrowerDAOImpl borrowerDAO;
#InjectMocks
BorrowerService borrowerService;
#BeforeClass
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void persistTest() {
Borrower borrower = new Borrower.BorrowerBuilder().firstName("Lars").lastName("Urlich").adress("LA")
.phoneNumber("900900990").build();
borrowerService.persist(borrower);
List<Borrower> borrowerList = borrowerService.getBorrowerByName("Lars Urlich");
Assert.assertEquals(true, borrower.equals(borrowerList.get(0)));
}
}
My BorrowerService:
#Service("borrowerService")
#Transactional
public class BorrowerService {
#Autowired
private BorrowerDAO borrowerDAO;
public List<Borrower> getBorrowers() {
return borrowerDAO.getBorrowers();
}
public List<Borrower> getBorrowerByName(String name) {
return borrowerDAO.getBorrowerByName(name);
}
public boolean removeBorrower(Borrower borrower) {
return borrowerDAO.removeBorrower(borrower);
}
public boolean persist(Borrower borrower) {
return borrowerDAO.persist(borrower);
}
}
My BorrowerDAOImpl:
#Repository("borrowerDAO")
#Transactional
public class BorrowerDAOImpl extends DAO implements BorrowerDAO {
#Override
public List<Borrower> getBorrowers() {
List<Borrower> borrowerList = null;
Query query = entityManager.createQuery("SELECT B FROM Borrower B");
borrowerList = query.getResultList();
return borrowerList;
}
#Override
public List<Borrower> getBorrowerByName(String name) {
List<Borrower> borrowerList = null;
String[] values = name.split(" ");
Query query = entityManager.createQuery("SELECT B FROM Borrower B WHERE B.firstName LIKE '" + values[0]
+ "' AND B.lastName LIKE '" + values[1] + "'");
borrowerList = query.getResultList();
return borrowerList;
}
#Override
public boolean removeBorrower(Borrower borrower) {
String firstName = borrower.getFirstName();
String lastName = borrower.getLastName();
Query query = entityManager
.createQuery("DELETE Borrower where FIRST_NAME LIKE :FirstName AND LAST_NAME LIKE :LastName");
query.setParameter("FirstName", firstName);
query.setParameter("LastName", lastName);
query.executeUpdate();
return true;
}
#Override
public boolean persist(Borrower borrower) {
entityManager.persist(borrower);
return true;
}
}
and abstract DAO:
#Repository
#Transactional
public abstract class DAO {
#PersistenceContext
protected EntityManager entityManager;
}
Maven returns failure:
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.LinkedList.checkElementIndex(LinkedList.java:555)
at java.util.LinkedList.get(LinkedList.java:476)
at com.me.service.test.BorrowerServiceTest.persistTest(BorrowerServiceTest.java:41)
I also had to fight with this. The problem here is that your test runs in it's own transaction, so nothing will be committed during method's execution. Now here is what I did:
public class IntegrationTest extends SomeTestBase
{
#Autowired
private PlatformTransactionManager platformTransactionManager;
private TransactionTemplate transactionTemplate;
#Autowired
private BeanToTest beanToTest;
#Override
#Before
public void setup()
{
super.setup();
this.transactionTemplate = new TransactionTemplate(this.platformTransactionManager);
}
#Test
public void fooTest()
{
// given
// when
boolean result = this.transactionTemplate.execute(new TransactionCallback<Boolean>()
{
#Override
public Boolean doInTransaction(TransactionStatus status)
{
return IntegrationTest.this.beanToTest.foo();
}
});
// then
}
}
This allows you to have methods execute within a separate transaction. Please note that you might declare some variables as final.
Hope that helps.
Check the Spring documentation: it looks your test class should extend AbstractTestNGSpringContextTests.
Use #Commit annotation on the whole test class or even method to persist changes made in the test. For more information https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#commit
I'm just starting with spring and hibernate. I'm trying to create some basic service using DAO.
Here is one of it:
#SuppressWarnings("unchecked")
#Override
public Users findByUserId(int id) {
List<Users> users = new ArrayList<Users>();
if(getSessionFactory() != null) {
try {
session = getSessionFactory().getCurrentSession();
users = session
.createQuery("from Users where id=?")
.setParameter(0, id)
.list();
} catch (HibernateException e) {
LOGGER.error("HibernateException: " + e);
}
}
if (!users.isEmpty()) {
return users.get(0);
} else {
return null;
}
}
And I called this service from a controller:
#RestController
public class JSONController {
#Autowired
private UserDao userDao;
#RequestMapping(value = "/rest/userbyid/{id}",
method = RequestMethod.GET,
headers = "Accept=application/json")
public Users getUserById(#PathVariable("id") int id) {
return userDao.findByUserId(id);
}
}
I understand that the session had been closed when the process come to controller. I can solve this by using openSession() method.
I just want to know is there any better way to handle this? Better still using getCurrentSession() (or any).
It's not good to return Entity to be serialized in controller. Imagine serializer which invokes all methods and even lazy collections.
For User instance it calls let's say getProjects() lazy method, then for each Project returned it agains call getUser() and so on.
Good practice is to define Service layer and return DTO (Data Transfer Object) which contains only necessary fields.
There is alternative approach to unproxy entities before return defining depth.
#SuppressWarnings("unchecked")
protected T unproxy(T entity){
if (entity == null) {
return null;
}
if (entity instanceof HibernateProxy) {
try {
Hibernate.initialize(entity);
} catch (ObjectNotFoundException e) {
return null;
}
entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
return entity;
}
From
https://gist.github.com/maikelsperandio/6889130
We are trying to use autowiring in our webservice, but this doens't seem to work (generates nullPointer). We have been searching for a solution for quite a long time, but did not succeed.
Our webservice:
#WebService(wsdlLocation = "/WEB-INF/wsdl/contract.wsdl", serviceName = "BookingService", targetNamespace = "http://realdolmen.com/", portName = "BookingServicePortType")
public class BookingService extends SpringBeanAutowiringSupport implements BookingServicePortType {
#Autowired
BookingServiceBean bookingServiceBean;
#Autowired
TariffService tariffService;
#Override
public BookingResponse createBooking(#WebParam(name = "bookingInput", targetNamespace = "http://realdolmen.com/", partName = "tariffId") BookingInput input) {
Tariff tariff = tariffService.getTariffById(input.getTariffId());
Booking booking = new Booking.BookingBuilder().withBaggageAllowance(tariff.getFlight().getBaggageAllowance())
.withDayOfDeparture(input.getDayOfDeparture()).withHourOfDeparture(input.getHourOfDeparture()).withTariff(tariff).withDuration(input.getDuration()).createBooking();
bookingServiceBean.createBooking(booking);
BookingResponse bookingResponse = new BookingResponse();
bookingResponse.setBookingId(booking.getId());
bookingResponse.setBaggageAllowance(booking.getBaggageAllowance());
bookingResponse.setDayOfDeparture(createWeirdDateClass(booking.getDayOfDeparture()));
bookingResponse.setDuration(booking.getDuration());
bookingResponse.setHourOfDeparture(booking.getHourOfDeparture());
return bookingResponse;
}
private XMLGregorianCalendar createWeirdDateClass(String lexicalRepresentation) {
try {
return DatatypeFactory.newInstance().newXMLGregorianCalendar(lexicalRepresentation);
} catch (DatatypeConfigurationException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
return null;
}
}
}
our spring service:
#Service
#Transactional
public class BookingServiceBeanImpl implements BookingServiceBean {
#Autowired
BookingDAO bookingDAO;
#Override public void createBooking(Booking booking) {
bookingDAO.createBooking(booking);
}
}
The spring bean can be used in the spring controllers so I don't think there's a problem there..