Transaction using JSF2, EJB3, JPA2 - jpa

What is the best way to handle transactions in this environment?
I have a Transacao class, which has a collection of Transacao.
public class Transacao {
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pai")
private List<Transacao> filhos;
}
I load this in JSF from a EJB, something like:
public class TransacaoBean {
#EJB
private TransacaoService transacaoService;
private void edit(Long id) {
this.transacao = transacaoService.findById(id);
}
}
although, if I want to get the collection of filhos, I have to do this:
public class TransacaoBean {
...
private void edit(Long id) {
this.transacao = transacaoService.findById(id);
log.info(this.transacao.getFilhos.size()); //this throws a LazyInitializationException
}
}
and I get an Exception.
What is the best way to have this loaded in my JSF? I'm considering creating a Filter and using USerTransaction to keep the transaction open for the request or fetching the filhos in my EJB. Is there a better solution to this, which one is better?

The fetch's default value of the #OneToMany is FetchType.LAZY.
You can set it FetchType.EAGER to use them in non-managed environment.
Or you can make another EJB or method for getting a list or just the size.
public class TransacaoService {
public Transacao findById(final long id) {
...
}
public long getFilhosSize(final long id) {
// SELECT f FROM Transacao AS t WHERE t.pai.id=:id
}
#PersistenceContext
private EntityManager entityManager;
}

Related

Injecting Services in Entity Listener ...?

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

Why Lazy Collections do not work with JavaFX getters / setters?

I experienced poor performance when using em.find(entity, primaryKey).
The reason seems to be that em.find() will also load entity collections, that are annotated with FetchType.LAZY.
This small test case illustrates what I mean:
public class OriginEntityTest4 {
[..]
#Test
public void test() throws Exception {
final OriginEntity oe = new OriginEntity("o");
final ReferencePeakEntity rpe = new ReferencePeakEntity();
oe.getReferencePeaks().add(rpe);
DatabaseAccess.onEntityManager(em -> {
em.persist(oe);
em.persist(rpe);
});
System.out.println(rpe.getEntityId());
DatabaseAccess.onEntityManager(em -> {
em.find(OriginEntity.class, oe.getEntityId());
});
}
}
#Access(AccessType.PROPERTY)
#Entity(name = "Origin")
public class OriginEntity extends NamedEntity {
[..]
private final ListProperty<ReferencePeakEntity> referencePeaks =
referencePeaks =
new SimpleListProperty<>(FXCollections.observableArrayList(ReferencePeakEntity.extractor()));
#Override
#OneToMany(mappedBy = "origin", fetch = FetchType.LAZY)
public final List<ReferencePeakEntity> getReferencePeaks() {
return this.referencePeaksProperty().get();
}
public final void setReferencePeaks(final List<ReferencePeakEntity> referencePeaks) {
this.referencePeaksProperty().setAll(referencePeaks);
}
}
I cannot find any documentation on that, my question is basically how can I prevent the EntityManager from loading the lazy collection?
Why I need em.find()?
I use the following method to decide whether I need to persist a new entity or update an existing one.
public static void mergeOrPersistWithinTransaction(final EntityManager em, final XIdentEntity entity) {
final XIdentEntity dbEntity = em.find(XIdentEntity.class, entity.getEntityId());
if (dbEntity == null) {
em.persist(entity);
} else {
em.merge(entity);
}
}
Note that OriginEntity is a JavaFX bean, where getter and setter delegate to a ListProperty.
Because FetchType.LAZY is only a hint. Depending on the implementation and how you configured your entity it will be able to do it or not.
Not an answer to titles question but maybe to your problem.
You can use also em.getReference(entityClass, primaryKey) in this case. It should be more efficient in your case since it just gets a reference to possibly existing entity.
See When to use EntityManager.find() vs EntityManager.getReference()
On the other hand i think your check is perhaps not needed. You could just persist or merge without check?
See JPA EntityManager: Why use persist() over merge()?

Injecting an EJB into an Automatic Timer EJB returns null

I'm trying to develop e very simple app based on a running thread creating entities in a DB every second in JavaEE on a Glassfish4 Server.
I'm using an Automatic Timer, where I inject an EJB managing the persistence.
The Timer Service is the following one:
#Singleton
#LocalBean
#Startup
public class UpdateEJB {
#EJB
MeasureEJB measureEjb;
#Schedule(second = "*/1", minute = "*", hour = "*", persistent = false)
public void doWork() {
measureEjb.create(new Measure());
}
}
While the EJB is:
#Stateless
public class MeasureEJB {
#PersistenceContext(unitName = "smarthomePU")
private EntityManager em;
public Measure create (Measure _measure) {
em.persist(_measure);
return _measure;
}
}
The Entity
#Entity
public class Measure implements Serializable {
#Id
private String time;
private int[] temp;
private boolean[] water;
public int[] getTemp() {
return temp;
}
public void setTemp(int[] temp) {
this.temp = temp;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public boolean[] getWater() {
return water;
}
public void setWater(boolean[] water) {
this.water = water;
}
private static final long serialVersionUID = 1L;
public Measure() {
super();
}
public Measure(int[] _temp, boolean[] _water) {
temp = _temp;
water = _water;
time = "";
}
}
But when I try to use the MeasureEJB in the UpdateEJB the app stops with a NPE on the create method. What am I doing wrong?
From the code fragments above, I cannot see how EntityManager is injected and since your're talking about an NPE the problem may lie there.
Also avoid #Singleton(s) if you don't keep state in your beans. By default your public void doWork() is associated with a Write Lock automatically.

Avoiding loading LAZY collection in Spring Data Jpa

I have following relationship:
#Entity class Shop {
#OneToMany(mappedBy = "shop", fetch = LAZY)
private List<Employee> employees = new LinkedList<>();
}
and
#Entity class Employee {
#ManyToOne
private Shop shop;
}
I've declared Spring Data repository like this:
public interface ShopRepository extends JpaRepository<Shop, Long> {}
Calling ShopRepository#findOne(id) method forces fetching of the List<Employee> employees which is LAZY relationship.
I have service which uses Shop repository:
#Service
#Transactional(readOnly = true)
public class ShopService {
private final ShopRepository shopRepository;
#Autowired
public ShopService(ShopRepository shopRepository) {
this.shopRepository = shopRepository;
}
public Shop find(Long id) {
return shopRepository.findOne(id);
}
}
The service method is called within another controller method:
#RequestMapping(value = "api/schedule/{shopId:[0-9]+}/{date:\\d{4}-\\d{2}-\\d{2}}", method = RequestMethod.GET)
#ResponseBody
public Schedule getSchedule(#PathVariable Long shopId,
#PathVariable #DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) {
Schedule schedule = scheduleService.findSchedule(shopId, date);
if(schedule != null)
return schedule;
else {
Shop shop = shopService.find(shopId);
Schedule empty = new Schedule(shop, date);
return empty;
}
}
How to get rid of fetching employees relationship?
I found solution.
Actually I used #JsonManagedReference/#JsonBackRefernce on my entity to prevent cycling while marshaling to JSON. It causes fetching LAZY loading data.
To avoid this you should add Hibernate4Module to MappingJackson2HttpMessageConverter.
More info at this post: Avoid Jackson serialization on non fetched lazy objects

Spring Data MongoDB No property get found for type at org.springframework.data.mapping.PropertyPath

I am using Spring Data MongodB 1.4.2.Release version. For Spring Data MongoDB, I have created the custom repository interface and implementation in one location and create custom query function getUsersName(Users users).
However I am still getting below exception:
Caused by: org.springframework.data.mapping.PropertyReferenceException:
No property get found for type Users! at org.springframework.data.mapping.PropertyPath. (PropertyPath.java:75) at
org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:327) at
org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:359) at
org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:359) at
org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:307) at
org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:270) at
org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:241) at
org.springframework.data.repository.query.parser.Part.(Part.java:76) at
org.springframework.data.repository.query.parser.PartTree$OrPart.(PartTree.java:201) at
org.springframework.data.repository.query.parser.PartTree$Predicate.buildTree(PartTree.java:291) at
org.springframework.data.repository.query.parser.PartTree$Predicate.(PartTree.java:271) at
org.springframework.data.repository.query.parser.PartTree.(PartTree.java:80) at
org.springframework.data.mongodb.repository.query.PartTreeMongoQuery.(PartTreeMongoQuery.java:47)
Below is my Spring Data MongoDB structure:
/* Users Domain Object */
#Document(collection = "users")
public class Users {
#Id
private ObjectId id;
#Field ("last_name")
private String last_name;
#Field ("first_name")
private String first_name;
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public String getFirst_name() {
return first_name;
}
public void setFirst_name(String first_name) {
this.first_name = first_name;
}
}
/* UsersRepository.java main interface */
#Repository
public interface UsersRepository extends MongoRepository<Users,String>, UsersRepositoryCustom {
List findUsersById(String id);
}
/* UsersRepositoryCustom.java custom interface */
#Repository
public interface UsersRepositoryCustom {
List<Users> getUsersName(Users users);
}
/* UsersRepositoryImpl.java custom interface implementation */
#Component
public class UsersRepositoryImpl implements UsersRepositoryCustom {
#Autowired
MongoOperations mongoOperations;
#Override
public List<Users> getUsersName(Users users) {
return mongoOperations.find(
Query.query(Criteria.where("first_name").is(users.getFirst_name()).and("last_name").is(users.getLast_name())), Users.class);
}
/* Mongo Test function inside Spring JUnit Test class calling custom function with main UsersRepository interface */
#Autowired
private UsersRepository usersRepository;
#Test
public void getUsersName() {
Users users = new Users();
users.setFirst_name("James");`enter code here`
users.setLast_name("Oliver");
List<Users> usersDetails = usersRepository.getUsersName(users);
System.out.println("users List" + usersDetails.size());
Assert.assertTrue(usersDetails.size() > 0);
}
The query method declaration in your repository interface is invalid. As clearly stated in the reference documentation, query methods need to start with get…By, read_By, find…By or query…by.
With custom repositories, there shouldn't be a need for method naming conventions as Oliver stated. I have mine working with a method named updateMessageCount
Having said that, I can't see the problem with the code provided here.
I resolved this issue with the help of this post here, where I wasn't naming my Impl class correctly :
No property found for type error when try to create custom repository with Spring Data JPA