Thoughts and learned lessons
Random thoughts on programming and life in general
Wednesday, December 10, 2014
Finding an oracle constraint by name
SELECT owner, table_name
FROM user_constraints
WHERE constraint_name = <<your constraint name>>
or if you have sysadm privileges:
SELECT owner, table_name
FROM dba_constraints
WHERE constraint_name = <<your constraint name>>
Thursday, March 13, 2014
Grails: Getting the Vaadin plugin to run. "Can not process requests before init() has been called"
I had the problem after I installed the grails-vaadin plugin when starting my application I would get the following error
There is a bug in the GrailsVaadinServlet where you have to add the service.init() call.
Fortunately when you install the plugin you edit the source code as it is downloaded to your grails project. Mine was found here:
There is a bug in the GrailsVaadinServlet where you have to add the service.init() call.
Fortunately when you install the plugin you edit the source code as it is downloaded to your grails project. Mine was found here:
Wednesday, March 5, 2014
How to finally solve the Hibernate Lazy Load problem: Make the Collection reconnectable
The problem
After years and years working with hibernate there are a few things I hate about it.The logging and the error messages are not clear and sometimes misleading (I will not expound now) and then the most common problem of all, the lazy load exception.
There are solutions like SessionInView pattern etc, but I and thousands of others wonder why it is so complicated or bad to make the Collection reconnect itself when needed.
I mean eclipse link does it also with a readonly connection.
The solution
So here is my solution and it finally seems to work. I actually implemented Collection class that does the reconnecting for me.For this to work i have to do several steps
In the hibernate mapping define field access.
You can do this with annotations or if there is hibernate mapping file it looks like this.
At the top do:
..
In the entity in the getter of a relationship I return a wrapper class
public class MyEntity{
//..
Collection
public Collection
return new LazyCollectionWithReconnect
(customers, this, new MyProjectRelationshipInitializer());
}
}
The implementation of the wrapper class is in the end of this post
The RelationShipInitializer
The interesting stuff is in MyProjectRelationshipInitializerWe have a generic interface:
public interface RelationshipInitializer {
void initializeRelationship(Object entity, Object propertyValue);
}
That must be implemented by the project
Here I lookup a Stateless sessionbean that has access to the PersistenceContext and does the loading of the relationship
public class MyProjectRelationshipInitializer implements RelationshipInitializer{
@Override
public void initializeRelationship(Object entity, Object propertyValue) {
MyGenericServiceLocator.inst().getGenericPersistenceService()
.initializeRelationship(entity, propertyValue);
}
}
The GenericPersistenceServiceBean that actually initializes the hibernate proxy
looks like this:@Stateless
@Local(GenericPersistenceService.class)
public class GenericPersistenceServiceBean implements GenericPersistenceService
{
@PersistenceContext
protected EntityManager em;
@Override
public void initializeRelationship(Object entity, Object relationShipObject) {
org.hibernate.Session session = getHibernateSession();
// the lock method adds the entity back into the Entitymanager makes it
//managed.
try {
session.lock(entity, LockMode.NONE);
if(!Hibernate.isInitialized(relationShipObject))
{
Hibernate.initialize(relationShipObject);
}
} catch (TransientObjectException e) {
//ignore object that are not saved yet
}
}
private Session getHibernateSession() {
//on web as
if (em.getDelegate() instanceof Session){
return (Session) em.getDelegate();
}
//in openejb
if (em.getDelegate() instanceof HibernateEntityManager){
HibernateEntityManager e = (HibernateEntityManager) em.getDelegate();
return (Session) e.getDelegate();
}
throw new IllegalStateException(String.format("Invalid type of entity manager %s (%s). Expected it to be org.hibernate.Session or org.hibernate.ejb.HibernateEntityManager", em, em.getClass()));
}
}
Note that the getHibernateSession() is a little bit J2EE Server dependent and might be different for your vendor.
The LazyColletionWithReconnect implementation
is rather boring:public class LazyCollectionWithReconnect
private Collection
private Object surroundingEntity;
private RelationShipInitializer relationShipInitializer;
public LazyCollectionWithReconnect(Collection
super();
this.srcCollection = srcCollection;
this.surroundingEntity = surroundingEntity;
this.relationShipInitializer = relationShipInitializer;
}
protected void reconnectIfNecessary() {
ensureRelationIsLoaded(
this.surroundingEntity,
this.srcCollection,
this.relationShipInitializer
);
}
public static boolean ensureRelationIsLoaded(
Object entity,
Object propertyValue,
RelationShipInitializer initializer) {
boolean wasLoaded = false;
// first check
if(!Hibernate.isInitialized(propertyValue)){
initializer
.initializeRelationship(entity, propertyValue);
wasLoaded = true;
}
return wasLoaded;
}
public boolean add(E e) {
reconnectIfNecessary();
return srcCollection.add(e);
}
public boolean addAll(Collection c) {
reconnectIfNecessary();
return srcCollection.addAll(c);
}
public void clear() {
reconnectIfNecessary();
srcCollection.clear();
}
public boolean contains(Object o) {
reconnectIfNecessary();
return srcCollection.contains(o);
}
public boolean containsAll(Collection c) {
reconnectIfNecessary();
return srcCollection.containsAll(c);
}
public boolean equals(Object o) {
return srcCollection.equals(o);
}
public int hashCode() {
return srcCollection.hashCode();
}
public boolean isEmpty() {
reconnectIfNecessary();
return srcCollection.isEmpty();
}
public Iterator
reconnectIfNecessary();
return srcCollection.iterator();
}
public boolean remove(Object o) {
reconnectIfNecessary();
return srcCollection.remove(o);
}
reconnectIfNecessary();
return srcCollection.removeAll(c);
}
reconnectIfNecessary();
return srcCollection.retainAll(c);
}
reconnectIfNecessary();
return srcCollection.size();
}
reconnectIfNecessary();
return srcCollection.toArray();
}
public
reconnectIfNecessary();
return srcCollection.toArray(a);
}
}
Some common problems
HibernateException "reassociated object has dirty collection reference"
This error message actually can be misleading. In my case it stemmed from that the entity with the collection did not have equals and hashCode overridendeep cloning
Here is a small utility to really clone an object by writing it first to outputstream and back.
public static Object deepClone(Object src) throws IOException,ClassNotFoundException{
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(src);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ClassLoaderObjectInputStream ois = new ClassLoaderObjectInputStream(src.getClass().getClassLoader(),bais);
Object deepCopy = ois.readObject();
return deepCopy;
}
The class ClassLoaderObjectInputInputStream is needed to resolve the class if it is not in the same jar as the utility method deepClone
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectStreamClass;
import java.io.StreamCorruptedException;
/**
* A special ObjectInputStream that loads a class based on a specified
*
*
* This is useful in dynamic container environments.
*
* @author Paul Hammant
* @version $Id: ClassLoaderObjectInputStream.java 437567 2006-08-28 06:39:07Z bayard $
* @since Commons IO 1.1
*/
public class ClassLoaderObjectInputStream extends ObjectInputStream {
/** The class loader to use. */
private ClassLoader classLoader;
/**
* Constructs a new ClassLoaderObjectInputStream.
*
* @param classLoader the ClassLoader from which classes should be loaded
* @param inputStream the InputStream to work on
* @throws IOException in case of an I/O error
* @throws StreamCorruptedException if the stream is corrupted
*/
public ClassLoaderObjectInputStream(
ClassLoader classLoader, InputStream inputStream)
throws IOException, StreamCorruptedException {
super(inputStream);
this.classLoader = classLoader;
}
/**
* Resolve a class specified by the descriptor using the
* specified ClassLoader or the super ClassLoader.
*
* @param objectStreamClass descriptor of the class
* @return the Class object described by the ObjectStreamClass
* @throws IOException in case of an I/O error
* @throws ClassNotFoundException if the Class cannot be found
*/
protected Class resolveClass(ObjectStreamClass objectStreamClass)
throws IOException, ClassNotFoundException {
Class clazz = Class.forName(objectStreamClass.getName(), false, classLoader);
if (clazz != null) {
// the classloader knows of the class
return clazz;
} else {
// classloader knows not of class, let the super classloader do it
return super.resolveClass(objectStreamClass);
}
}
}
public static Object deepClone(Object src) throws IOException,ClassNotFoundException{
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(src);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ClassLoaderObjectInputStream ois = new ClassLoaderObjectInputStream(src.getClass().getClassLoader(),bais);
Object deepCopy = ois.readObject();
return deepCopy;
}
The class ClassLoaderObjectInputInputStream is needed to resolve the class if it is not in the same jar as the utility method deepClone
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectStreamClass;
import java.io.StreamCorruptedException;
/**
* A special ObjectInputStream that loads a class based on a specified
*
ClassLoader
rather than the system default.*
* This is useful in dynamic container environments.
*
* @author Paul Hammant
* @version $Id: ClassLoaderObjectInputStream.java 437567 2006-08-28 06:39:07Z bayard $
* @since Commons IO 1.1
*/
public class ClassLoaderObjectInputStream extends ObjectInputStream {
/** The class loader to use. */
private ClassLoader classLoader;
/**
* Constructs a new ClassLoaderObjectInputStream.
*
* @param classLoader the ClassLoader from which classes should be loaded
* @param inputStream the InputStream to work on
* @throws IOException in case of an I/O error
* @throws StreamCorruptedException if the stream is corrupted
*/
public ClassLoaderObjectInputStream(
ClassLoader classLoader, InputStream inputStream)
throws IOException, StreamCorruptedException {
super(inputStream);
this.classLoader = classLoader;
}
/**
* Resolve a class specified by the descriptor using the
* specified ClassLoader or the super ClassLoader.
*
* @param objectStreamClass descriptor of the class
* @return the Class object described by the ObjectStreamClass
* @throws IOException in case of an I/O error
* @throws ClassNotFoundException if the Class cannot be found
*/
protected Class resolveClass(ObjectStreamClass objectStreamClass)
throws IOException, ClassNotFoundException {
Class clazz = Class.forName(objectStreamClass.getName(), false, classLoader);
if (clazz != null) {
// the classloader knows of the class
return clazz;
} else {
// classloader knows not of class, let the super classloader do it
return super.resolveClass(objectStreamClass);
}
}
}
Tuesday, March 4, 2014
Hibernate Lazy Load exception and how to load an relationship
Hibernate and lazy loading sucks. Especially in Web Dynpro where we cannot use the Session in View pattern. Therefore there is handy method can load a collection to make sure that a collection is loaded and load it on demand from the service layer
public abstract class GenericDaoBean
// ....
public void initializeRelationship(T entity, String property) {
org.hibernate.Session session = getHibernateSession();
// the lock method adds the entity back into the Entitymanager makes it managed.
try {
session.lock(entity, LockMode.NONE);
Object collectionProxy = getAttributeValue(entity, property);
if(!Hibernate.isInitialized(collectionProxy))
{
Hibernate.initialize(collectionProxy);
}
} catch (TransientObjectException e) {
//ignore object that are not saved yet
}
}
public org.hibernate.Session getHibernateSession() {
Object delegate = getEntityManager().getDelegate();
org.hibernate.Session session = null;
//This is in SAP J2EE
if(delegate instanceof org.hibernate.Session){
session = (org.hibernate.Session) delegate;
}
// this is in OpenEJB container
else if(delegate instanceof HibernateEntityManager){
HibernateEntityManager hbEm = (HibernateEntityManager) delegate;
session = hbEm.getSession();
}
return session;
}
}
public static Object getAttributeValue(Object bean, String attributeName){
Map
PropertyDescriptor desc = props.get(attributeName);
if(desc == null) throw new IllegalArgumentException("attribute:" +attributeName + " does not exist in bean "+ bean);
try {
Object result = desc.getReadMethod().invoke(bean, null);
return result;
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
Subscribe to:
Posts (Atom)