X-Git-Url: http://wamblee.org/gitweb/?a=blobdiff_plain;f=support%2Fspring%2Fsrc%2Fmain%2Fjava%2Forg%2Fwamblee%2Fpersistence%2Fhibernate%2FHibernateSupport.java;h=aa52f0d4dd3f88e0ff7cff7b0b9c04ed0526437a;hb=ddd261f331280640c5b53c7128230b629ebcd268;hp=5012b02ff50ad46166550d3ec26b11553209661b;hpb=92e23e5ecf9614f2ab770a8cdedc0b21ddf1e127;p=utils diff --git a/support/spring/src/main/java/org/wamblee/persistence/hibernate/HibernateSupport.java b/support/spring/src/main/java/org/wamblee/persistence/hibernate/HibernateSupport.java index 5012b02f..aa52f0d4 100644 --- a/support/spring/src/main/java/org/wamblee/persistence/hibernate/HibernateSupport.java +++ b/support/spring/src/main/java/org/wamblee/persistence/hibernate/HibernateSupport.java @@ -1,69 +1,50 @@ /* * Copyright 2005 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ - package org.wamblee.persistence.hibernate; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.orm.hibernate3.HibernateTemplate; +import org.springframework.orm.hibernate3.support.HibernateDaoSupport; + +import org.wamblee.persistence.Persistent; + import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; + import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.orm.hibernate3.HibernateTemplate; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; -import org.wamblee.persistence.Persistent; /** - * Extension of - * {@link org.springframework.orm.hibernate.support.HibernateDaoSupport}. + * Extension of {@link + * org.springframework.orm.hibernate.support.HibernateDaoSupport}. * * @author Erik Brakkee */ public class HibernateSupport extends HibernateDaoSupport { - - private static final Log LOG = LogFactory.getLog(HibernateSupport.class); - /** - * This class provided an equality operation based on the object reference - * of the wrapped object. This is required because we cannto assume that the - * equals operation has any meaning for different types of persistent - * objects. This allows us to use the standard collection classes for - * detecting cyclic dependences and avoiding recursion. - * + * DOCUMENT ME! */ - private static final class ObjectElem { - private Object object; - - public ObjectElem(Object aObject) { - object = aObject; - } - - public boolean equals(Object aObj) { - return ((ObjectElem) aObj).object == object; - } - - public int hashCode() { - return object.hashCode(); - } - } + private static final Log LOG = LogFactory.getLog(HibernateSupport.class); - /** +/** * Constructs the object. * */ @@ -72,30 +53,26 @@ public class HibernateSupport extends HibernateDaoSupport { } /** - * Performes a hibernate Session.merge() and updates the - * object with the correct primary key and version. This is an extension to - * the hibernate merge operation because hibernate itself leaves the object - * passed to merge untouched. - * - * Use this method with extreme caution since it will recursively load all - * objects that the current object has relations with and for which - * cascade="merge" was specified in the Hibernate mapping file. - * - * @param aPersistent - * Object to merge. + * Performes a hibernate Session.merge() and updates + * the object with the correct primary key and version. This is an + * extension to the hibernate merge operation because hibernate itself + * leaves the object passed to merge untouched. Use this method with + * extreme caution since it will recursively load all objects that the + * current object has relations with and for which cascade="merge" was + * specified in the Hibernate mapping file. + * + * @param aPersistent Object to merge. */ public void merge(Persistent aPersistent) { merge(getHibernateTemplate(), aPersistent); } /** - * As {@link #merge(Persistent)} but with a given template. This method can - * be accessed in a static way. - * - * @param aTemplate - * Hibernate template - * @param aPersistent - * Object to merge. + * As {@link #merge(Persistent)} but with a given template. This + * method can be accessed in a static way. + * + * @param aTemplate Hibernate template + * @param aPersistent Object to merge. */ public static void merge(HibernateTemplate aTemplate, Persistent aPersistent) { Persistent merged = (Persistent) aTemplate.merge(aPersistent); @@ -103,79 +80,81 @@ public class HibernateSupport extends HibernateDaoSupport { } /** - * Copies primary keys and version from the result of the merged to the - * object that was passed to the merge operation. It does this by traversing - * the properties of the object. It copies the primary key and version for - * objects that implement {@link Persistent} and applies the same rules to - * objects in maps and sets as well (i.e. recursively). - * - * @param aPersistent - * Object whose primary key and version are to be set. - * @param aMerged - * Object that was the result of the merge. - * @param aProcessed - * List of already processed Persistent objects of the persistent - * part. + * Copies primary keys and version from the result of the merged to + * the object that was passed to the merge operation. It does this by + * traversing the properties of the object. It copies the primary key and + * version for objects that implement {@link Persistent} and applies the + * same rules to objects in maps and sets as well (i.e. recursively). + * + * @param aPersistent Object whose primary key and version are to be set. + * @param aMerged Object that was the result of the merge. + * @param aProcessed List of already processed Persistent objects of the + * persistent part. + * + * @throws RuntimeException DOCUMENT ME! */ public static void processPersistent(Persistent aPersistent, - Persistent aMerged, List aProcessed) { - if (aPersistent == null && aMerged == null) { + Persistent aMerged, List aProcessed) { + if ((aPersistent == null) && (aMerged == null)) { return; } - if (aPersistent == null || aMerged == null) { + + if ((aPersistent == null) || (aMerged == null)) { throw new RuntimeException("persistent or merged object is null '" - + aPersistent + "'" + " '" + aMerged + "'"); + + aPersistent + "'" + " '" + aMerged + "'"); } + ObjectElem elem = new ObjectElem(aPersistent); + if (aProcessed.contains(elem)) { return; // already processed. } + aProcessed.add(elem); LOG.debug("Setting pk/version on " + aPersistent + " from " + aMerged); - if (aPersistent.getPrimaryKey() != null + if ((aPersistent.getPrimaryKey() != null) && !aMerged.getPrimaryKey().equals(aPersistent.getPrimaryKey())) { LOG.error("Mismatch between primary key values: " + aPersistent - + " " + aMerged); + + " " + aMerged); } else { aPersistent.setPersistedVersion(aMerged.getPersistedVersion()); aPersistent.setPrimaryKey(aMerged.getPrimaryKey()); } Method[] methods = aPersistent.getClass().getMethods(); + for (Method getter : methods) { if (getter.getName().startsWith("get")) { Class returnType = getter.getReturnType(); try { if (Set.class.isAssignableFrom(returnType)) { - Set merged = (Set) getter.invoke(aMerged); + Set merged = (Set) getter.invoke(aMerged); Set persistent = (Set) getter.invoke(aPersistent); processSet(persistent, merged, aProcessed); } else if (List.class.isAssignableFrom(returnType)) { - List merged = (List) getter.invoke(aMerged); + List merged = (List) getter.invoke(aMerged); List persistent = (List) getter.invoke(aPersistent); processList(persistent, merged, aProcessed); } else if (Map.class.isAssignableFrom(returnType)) { - Map merged = (Map) getter.invoke(aMerged); + Map merged = (Map) getter.invoke(aMerged); Map persistent = (Map) getter.invoke(aPersistent); processMap(persistent, merged, aProcessed); } else if (Persistent.class.isAssignableFrom(returnType)) { - Persistent merged = (Persistent) getter.invoke(aMerged); - Persistent persistent = (Persistent) getter - .invoke(aPersistent); + Persistent merged = (Persistent) getter.invoke(aMerged); + Persistent persistent = (Persistent) getter.invoke(aPersistent); processPersistent(persistent, merged, aProcessed); } else if (returnType.isArray() - && Persistent.class.isAssignableFrom(returnType - .getComponentType())) { - Persistent[] merged = (Persistent[]) getter - .invoke(aMerged); - Persistent[] persistent = (Persistent[]) getter - .invoke(aPersistent); + && Persistent.class.isAssignableFrom( + returnType.getComponentType())) { + Persistent[] merged = (Persistent[]) getter.invoke(aMerged); + Persistent[] persistent = (Persistent[]) getter.invoke(aPersistent); + for (int i = 0; i < persistent.length; i++) { processPersistent(persistent[i], merged[i], - aProcessed); + aProcessed); } } } catch (InvocationTargetException e) { @@ -185,58 +164,60 @@ public class HibernateSupport extends HibernateDaoSupport { } } } - } /** * Process the persistent objects in the collections. - * - * @param aPersistent - * Collection in the original object. - * @param aMerged - * Collection as a result of the merge. - * @param aProcessed - * List of processed persistent objects. + * + * @param aPersistent Collection in the original object. + * @param aMerged Collection as a result of the merge. + * @param aProcessed List of processed persistent objects. + * + * @throws RuntimeException DOCUMENT ME! */ public static void processList(List aPersistent, List aMerged, - List aProcessed) { - Object[] merged = aMerged.toArray(); + List aProcessed) { + Object[] merged = aMerged.toArray(); Object[] persistent = aPersistent.toArray(); + if (merged.length != persistent.length) { throw new RuntimeException("Array sizes differ " + merged.length - + " " + persistent.length); + + " " + persistent.length); } + for (int i = 0; i < merged.length; i++) { assert merged[i].equals(persistent[i]); + if (merged[i] instanceof Persistent) { processPersistent((Persistent) persistent[i], - (Persistent) merged[i], aProcessed); + (Persistent) merged[i], aProcessed); } } } /** * Process the persistent objects in sets. - * - * @param aPersistent - * Collection in the original object. - * @param aMerged - * Collection as a result of the merge. - * @param aProcessed - * List of processed persistent objects. + * + * @param aPersistent Collection in the original object. + * @param aMerged Collection as a result of the merge. + * @param aProcessed List of processed persistent objects. + * + * @throws RuntimeException DOCUMENT ME! */ public static void processSet(Set aPersistent, Set aMerged, - List aProcessed) { + List aProcessed) { if (aMerged.size() != aPersistent.size()) { throw new RuntimeException("Array sizes differ " + aMerged.size() - + " " + aPersistent.size()); + + " " + aPersistent.size()); } + for (Object merged : aMerged) { // Find the object that equals the merged[i] for (Object persistent : aPersistent) { if (persistent.equals(merged)) { processPersistent((Persistent) persistent, - (Persistent) merged, aProcessed); + (Persistent) merged, aProcessed); + break; } } @@ -245,37 +226,62 @@ public class HibernateSupport extends HibernateDaoSupport { /** * Process the Map objects in the collections. - * - * @param aPersistent - * Collection in the original object. - * @param aMerged - * Collection as a result of the merge. - * @param aProcessed - * List of processed persistent objects. + * + * @param aPersistent Collection in the original object. + * @param aMerged Collection as a result of the merge. + * @param aProcessed List of processed persistent objects. + * + * @throws RuntimeException DOCUMENT ME! */ public static void processMap(Map aPersistent, Map aMerged, - List aProcessed) { + List aProcessed) { if (aMerged.size() != aPersistent.size()) { throw new RuntimeException("Sizes differ " + aMerged.size() + " " - + aPersistent.size()); + + aPersistent.size()); } + Set keys = aMerged.keySet(); + for (Object key : keys) { if (!aPersistent.containsKey(key)) { throw new RuntimeException("Key '" + key + "' not found"); } - Object mergedValue = aMerged.get(key); + + Object mergedValue = aMerged.get(key); Object persistentValue = aPersistent.get(key); + if (mergedValue instanceof Persistent) { if (persistentValue instanceof Persistent) { processPersistent((Persistent) persistentValue, - (Persistent) mergedValue, aProcessed); + (Persistent) mergedValue, aProcessed); } else { throw new RuntimeException( - "Value in original object is null, whereas merged object contains a value"); + "Value in original object is null, whereas merged object contains a value"); } } } } + /** + * This class provided an equality operation based on the object + * reference of the wrapped object. This is required because we cannto + * assume that the equals operation has any meaning for different types of + * persistent objects. This allows us to use the standard collection + * classes for detecting cyclic dependences and avoiding recursion. + */ + private static final class ObjectElem { + private Object object; + + public ObjectElem(Object aObject) { + object = aObject; + } + + public boolean equals(Object aObj) { + return ((ObjectElem) aObj).object == object; + } + + public int hashCode() { + return object.hashCode(); + } + } }