001: /*
002: * Copyright 2005 Joe Walker
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.directwebremoting.hibernate;
017:
018: import java.beans.BeanInfo;
019: import java.beans.IntrospectionException;
020: import java.beans.Introspector;
021: import java.beans.PropertyDescriptor;
022: import java.lang.reflect.Method;
023: import java.util.HashMap;
024: import java.util.Map;
025:
026: import org.apache.commons.logging.LogFactory;
027: import org.apache.commons.logging.Log;
028: import org.directwebremoting.convert.BeanConverter;
029: import org.directwebremoting.convert.PlainProperty;
030: import org.directwebremoting.extend.Converter;
031: import org.directwebremoting.extend.MarshallException;
032: import org.directwebremoting.extend.Property;
033: import org.hibernate.Hibernate;
034: import org.hibernate.engine.SessionImplementor;
035: import org.hibernate.proxy.HibernateProxy;
036: import org.hibernate.proxy.LazyInitializer;
037:
038: /**
039: * BeanConverter that works with Hibernate to get BeanInfo.
040: * @author Joe Walker [joe at getahead dot ltd dot uk]
041: */
042: public class H3BeanConverter extends BeanConverter implements Converter {
043: /* (non-Javadoc)
044: * @see org.directwebremoting.convert.BeanConverter#getPropertyMapFromObject(java.lang.Object, boolean, boolean)
045: */
046: @Override
047: public Map<String, Property> getPropertyMapFromObject(
048: Object example, boolean readRequired, boolean writeRequired)
049: throws MarshallException {
050: Class<?> clazz = getClass(example);
051:
052: try {
053: BeanInfo info = Introspector.getBeanInfo(clazz);
054: PropertyDescriptor[] descriptors = info
055: .getPropertyDescriptors();
056:
057: Map<String, Property> properties = new HashMap<String, Property>();
058: for (PropertyDescriptor descriptor : descriptors) {
059: String name = descriptor.getName();
060:
061: // We don't marshall getClass()
062: if ("class".equals(name)) {
063: continue;
064: }
065:
066: // And this is something added by hibernate
067: if ("hibernateLazyInitializer".equals(name)) {
068: continue;
069: }
070:
071: // Access rules mean we might not want to do this one
072: if (!isAllowedByIncludeExcludeRules(name)) {
073: continue;
074: }
075:
076: if (readRequired && descriptor.getReadMethod() == null) {
077: continue;
078: }
079:
080: if (writeRequired
081: && descriptor.getWriteMethod() == null) {
082: continue;
083: }
084:
085: if (!assumeSession) {
086: // We don't marshall un-initialized properties for
087: // Hibernate3
088: Method method = findGetter(example, name);
089:
090: if (method == null) {
091: log.warn("Failed to find property: " + name);
092:
093: properties.put(name, new PlainProperty(name,
094: null));
095: continue;
096: }
097:
098: if (!Hibernate.isPropertyInitialized(example, name)) {
099: properties.put(name, new PlainProperty(name,
100: null));
101: continue;
102: }
103:
104: // This might be a lazy-collection so we need to double check
105: Object retval = method.invoke(example);
106: if (!Hibernate.isInitialized(retval)) {
107: properties.put(name, new PlainProperty(name,
108: null));
109: continue;
110: }
111: }
112:
113: properties.put(name, new H3PropertyDescriptorProperty(
114: descriptor));
115: }
116:
117: return properties;
118: } catch (Exception ex) {
119: throw new MarshallException(clazz, ex);
120: }
121: }
122:
123: /**
124: * Hibernate makes {@link Class#getClass()} diffficult ...
125: * @param example The class that we want to call {@link Class#getClass()} on
126: * @return The type of the given object
127: */
128: public Class<?> getClass(Object example) {
129: if (example instanceof HibernateProxy) {
130: HibernateProxy proxy = (HibernateProxy) example;
131: LazyInitializer initializer = proxy
132: .getHibernateLazyInitializer();
133: SessionImplementor implementor = initializer.getSession();
134:
135: if (initializer.isUninitialized()) {
136: try {
137: // getImplementation is going to want to talk to a session
138: if (implementor.isClosed()) {
139: // Give up and return example.getClass();
140: return example.getClass();
141: }
142: } catch (NoSuchMethodError ex) {
143: // We must be using Hibernate 3.0/3.1 which doesn't have
144: // this method
145: }
146: }
147:
148: return initializer.getImplementation().getClass();
149: } else {
150: return example.getClass();
151: }
152: }
153:
154: /**
155: * Cache the method if possible, using the classname and property name to
156: * allow for similar named methods.
157: * @param data The bean to introspect
158: * @param property The property to get the accessor for
159: * @return The getter method
160: * @throws IntrospectionException If Introspector.getBeanInfo() fails
161: */
162: protected Method findGetter(Object data, String property)
163: throws IntrospectionException {
164: Class<?> clazz = getClass(data);
165: // String key = clazz.getName() + ":" + property;
166:
167: Method method = null; // methods.get(key);
168: // if (method == null)
169: // {
170: PropertyDescriptor[] props = Introspector.getBeanInfo(clazz)
171: .getPropertyDescriptors();
172: for (PropertyDescriptor prop : props) {
173: if (prop.getName().equalsIgnoreCase(property)) {
174: method = prop.getReadMethod();
175: }
176: }
177:
178: // methods.put(key, method);
179: // }
180:
181: return method;
182: }
183:
184: /**
185: * @param assumeSession the assumeSession to set
186: */
187: public void setAssumeSession(boolean assumeSession) {
188: this .assumeSession = assumeSession;
189: }
190:
191: /**
192: * Do we assume there is an open session and read properties?
193: */
194: protected boolean assumeSession = false;
195:
196: /**
197: * The cache of method lookups that we've already done
198: */
199: //protected final Map<String, Method> methods = new HashMap<String, Method>();
200: /**
201: * The log stream
202: */
203: private static final Log log = LogFactory
204: .getLog(H3BeanConverter.class);
205: }
|