Cleanse Hibernate from my object but don't lazy load - java

I have an JPA+Hibernate entity that I need to send via RMI to a client that doesn't know Hibernate, so I've made a method to "cleanse" Hibernate from it:
// shortened
public class Player {
private Set<Item> ownedItems;
public void makeSerializable() {
ownedItems = new HashSet<Item>(ownedItems);
}
}
However, when I call makeSerializable Hibernate will attempt to lazy-load ownedItems if it's not loaded yet, which I don't want, and which is also impossible because there is Hibernate session. Instead, if ownedItems is not loaded, I'd like to set it to null or an empty set.
How can I do that?

if (!Hibernate.isInitialized(ownedItems)) {
ownedItems = new HashSet<Item>();
}
This is the way to test if a collection is initialized without the need for a session.

Related

Mockito argument matcher and hibernate lazyinitialization

I've created the following captor:
public class CompanyOwnerMatcher extends ArgumentMatcher<CompanyOwner> {
private String uuid;
CompanyOwnerMatcher(String uuid) {
this.uuid = uuid;
}
#Override
public boolean matches(Object arg) {
if (!(arg instanceof CompanyOwner)) return false;
CompanyOwner owner = (CompanyOwner) arg;
return Objects.equals(uuid, owner.getUuid());
}
}
I get an exception in this code:
Mockito.verify(payInApi).submit(eq(1L), argThat(new CompanyOwnerMatcher(expectedOwnerUuid)));
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:148)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:266)
CompanyOwner is managed by hibernate. It's weird, but after I catch a CompanyOwner, I can't get any field values on it because I get LazyInitializationException, even on fields that are not marked as Lazy.
Would appreciate any help with regards to this problem.
Thanks!
I believe, Hibernate creates some kind of proxy of CompanyOwner.
Then it really depends on the code, the chances are that by the time you call the matcher the object is already detached from Hibernate Session.
In this case, you'll get the LazyInitializationException when you try to access fields like you've mentioned.
Its really impossible to understand out of the supplied code snipped why exactly the hibernate decides to wrap the object with proxy, I can only suggest to place a breakpoint in matches method to make sure that this is proxy indeed but then you'll have to figure out the reason for making this proxy.
If you see that proxy is indeed must be done in this case, probably the best would be "re-attaching" the object to the session. The exception should disappear however you'll probably see that hibernate issues a DB request in this case.
You might also be interested in This thread
if your object looks like it is proxied by hibernate (not yet fetched from DB because the entity is marked as LAZY), you can find out and force unproxy like this:
public <T extends BaseObject> T unproxy(final T arg) {
if (arg instanceof HibernateProxy) {
return (T) Hibernate.unproxy(arg);
}
return arg;
}

Hibernate 5.2.9.Final cache not updated

I have a service (which I for some reason call controller) that is injected into the Jersey resource method.
#Named
#Transactional
public class DocCtrl {
...
public void changeDocState(List<String> uuids, EDocState state, String shreddingCode) throws DatabaseException, WebserviceException, RepositoryException, ExtensionException, LockException, AccessDeniedException, PathNotFoundException, UnknowException {
List<Document2> documents = doc2DAO.getManyByUUIDs(uuids);
for (Document2 doc : documents) {
if (EDocState.SOFT_DEL == state) {
computeShreddingFor(doc, shreddingCode); //here the state change happens and it is persisted to db
}
if (EDocState.ACTIVE == state)
unscheduleShredding(doc);
}
}
}
doc2DAO.getManyByUUIDs(uuids); gets an Entity object from the database.
#Repository
public class Doc2DAO {
#PersistenceContext(name = Vedantas.PU_NAME, type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;
public List<Document2> getManyByUUIDs(List<String> uuids) {
if (uuids.isEmpty())
uuids.add("-3");
TypedQuery<Document2> query = entityManager.createNamedQuery("getManyByUUIDs", Document2.class);
query.setParameter("uuids", uuids);
return query.getResultList();
}
}
However When I do second request to my API, I see state of this entity object unchanged, that means the same as before the logic above occoured.
In DB there is still changed status.
After the api service restart, I will get the entity in the correct state.
As I understand it, Hibernate uses it's L2 cache for the managed objects.
So can you, please point me to what I am doing wrong here? Obviously, I need to get cached entity with the changed state without service restart and I would like to keep entities attached to the persistence context for the performance reasons.
Now, can you tell me what I am
In the logic I am making some changes to this object. After the completition of the changeDocState method, the state is properly changed and persisted in the database.
Thanks for the answers;

GAE Objectify load object created in transaction within same transaction

I try to use objectify transaction, but I have some issues when I need to reload an object created in the same transaction.
Take this sample code
#Entity
public class MyObject
{
#Parent
Key<ParentClass> parent;
#Index
String foo;
}
ofy().transact(new VoidWork()
{
#Override
public void vrun()
{
ParentClass parent = load();// load the parent
String fooValue = "bar";
Key<ParentClass> parentKey = Key.create(ParentClass.class, parent.getId())
MyObject myObject = new MyObject(parentKey);
myObject.setFoo(fooValue);
ofy().save().entity(myObject).now();
MyObject reloaded = ofy().load().type(MyObject.class).ancestor(parentKey).filter("foo", fooValue).first().now();
if(reloaded == null)
{
throw new RuntimeException("error");
}
}
});
My object reloaded is always null, maybe I miss something, but logically within a transaction I can query an object which was created in the same transaction?
Thanks
Cloud Datastore differs from relational databases in this particular case. The documentation states that -
Unlike with most databases, queries and gets inside a Cloud Datastore
transaction do not see the results of previous writes inside that
transaction. Specifically, if an entity is modified or deleted within
a transaction, a query or lookup returns the original version of the
entity as of the beginning of the transaction, or nothing if the
entity did not exist then.
https://cloud.google.com/datastore/docs/concepts/transactions#isolation_and_consistency

Entity must be managed to call remove?

public Person deletePerson(Person entity) {
EntityManager ems = emf.createEntityManager();
try {
ems.getTransaction().begin();
ems.merge(entity);
ems.remove(entity);
ems.getTransaction().commit();
} finally {
ems.close();
}
return entity;
}
it doesnt work I don't know why? Gives me java.lang.IllegalArgumentException
It doesn't work because remove operation requires managed entity to be passed to it. You could modify your code like this to make it work:
entity = ems.merge(entity);
ems.remove(entity);
Because merge returns managed entity instance, you can call remove with the object it returns, because it is managed by JPA (the object you pass to merge is not affected, which is why your code fails).

Create a new object if current field is null in database

I have a database model class Project, and it has two embedded object fields:
#Embedded
public ContacterInfo contacter = new ContacterInfo();
#Embedded
public CompanyInfo company = new CompanyInfo();
'cause I don't want to check is null every time I use company and contacter, so I decided to create them anyway.
What I expected is, when there's nothing for contacter in database, Java would create a new ContacterInfo for me, and then I can just use it for new data. But in fact, I found contacter still could be set to null. I suspect that JPA load null from database and override my new create object with it.
How can I fix this ?
You can use the JPA Entity listeners (ObjectDB has a good explication). By example:
#PostLoad
void onPostLoad() {
if (contacter == null) {
contacter = new ContacterInfo();
}
if (company == null) {
company = new CompanyInfo();
}
}
Every time JPA load an instance of current entity, onPostLoad will be called.
Good luck!

Categories