Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » property » [javadoc | source]
    1   /*
    2    * Hibernate, Relational Persistence for Idiomatic Java
    3    *
    4    * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
    5    * indicated by the @author tags or express copyright attribution
    6    * statements applied by the authors.  All third-party contributions are
    7    * distributed under license by Red Hat Middleware LLC.
    8    *
    9    * This copyrighted material is made available to anyone wishing to use, modify,
   10    * copy, or redistribute it subject to the terms and conditions of the GNU
   11    * Lesser General Public License, as published by the Free Software Foundation.
   12    *
   13    * This program is distributed in the hope that it will be useful,
   14    * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   15    * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   16    * for more details.
   17    *
   18    * You should have received a copy of the GNU Lesser General Public License
   19    * along with this distribution; if not, write to:
   20    * Free Software Foundation, Inc.
   21    * 51 Franklin Street, Fifth Floor
   22    * Boston, MA  02110-1301  USA
   23    *
   24    */
   25   package org.hibernate.property;
   26   
   27   import java.beans.Introspector;
   28   import java.lang.reflect.InvocationTargetException;
   29   import java.lang.reflect.Method;
   30   import java.util.Map;
   31   
   32   import org.slf4j.Logger;
   33   import org.slf4j.LoggerFactory;
   34   
   35   import org.hibernate.HibernateException;
   36   import org.hibernate.PropertyAccessException;
   37   import org.hibernate.PropertyNotFoundException;
   38   import org.hibernate.engine.SessionFactoryImplementor;
   39   import org.hibernate.engine.SessionImplementor;
   40   import org.hibernate.util.ReflectHelper;
   41   
   42   /**
   43    * Accesses property values via a get/set pair, which may be nonpublic.
   44    * The default (and recommended strategy).
   45    * 
   46    * @author Gavin King
   47    */
   48   public class BasicPropertyAccessor implements PropertyAccessor {
   49   
   50   	private static final Logger log = LoggerFactory.getLogger(BasicPropertyAccessor.class);
   51   
   52   	public static final class BasicSetter implements Setter {
   53   		private Class clazz;
   54   		private final transient Method method;
   55   		private final String propertyName;
   56   
   57   		private BasicSetter(Class clazz, Method method, String propertyName) {
   58   			this.clazz=clazz;
   59   			this.method=method;
   60   			this.propertyName=propertyName;
   61   		}
   62   
   63   		public void set(Object target, Object value, SessionFactoryImplementor factory) 
   64   		throws HibernateException {
   65   			try {
   66   				method.invoke( target, new Object[] { value } );
   67   			}
   68   			catch (NullPointerException npe) {
   69   				if ( value==null && method.getParameterTypes()[0].isPrimitive() ) {
   70   					throw new PropertyAccessException(
   71   							npe, 
   72   							"Null value was assigned to a property of primitive type", 
   73   							true, 
   74   							clazz, 
   75   							propertyName
   76   						);
   77   				}
   78   				else {
   79   					throw new PropertyAccessException(
   80   							npe, 
   81   							"NullPointerException occurred while calling", 
   82   							true, 
   83   							clazz, 
   84   							propertyName
   85   						);
   86   				}
   87   			}
   88   			catch (InvocationTargetException ite) {
   89   				throw new PropertyAccessException(
   90   						ite, 
   91   						"Exception occurred inside", 
   92   						true, 
   93   						clazz, 
   94   						propertyName
   95   					);
   96   			}
   97   			catch (IllegalAccessException iae) {
   98   				throw new PropertyAccessException(
   99   						iae, 
  100   						"IllegalAccessException occurred while calling", 
  101   						true, 
  102   						clazz, 
  103   						propertyName
  104   					);
  105   				//cannot occur
  106   			}
  107   			catch (IllegalArgumentException iae) {
  108   				if ( value==null && method.getParameterTypes()[0].isPrimitive() ) {
  109   					throw new PropertyAccessException(
  110   							iae, 
  111   							"Null value was assigned to a property of primitive type", 
  112   							true, 
  113   							clazz, 
  114   							propertyName
  115   						);
  116   				}
  117   				else {
  118   					log.error(
  119   							"IllegalArgumentException in class: " + clazz.getName() +
  120   							", setter method of property: " + propertyName
  121   						);
  122   					log.error(
  123   							"expected type: " + 
  124   							method.getParameterTypes()[0].getName() +
  125   							", actual value: " + 
  126   							( value==null ? null : value.getClass().getName() )
  127   						);
  128   					throw new PropertyAccessException(
  129   							iae, 
  130   							"IllegalArgumentException occurred while calling", 
  131   							true, 
  132   							clazz, 
  133   							propertyName
  134   						);
  135   				}
  136   			}
  137   		}
  138   
  139   		public Method getMethod() {
  140   			return method;
  141   		}
  142   
  143   		public String getMethodName() {
  144   			return method.getName();
  145   		}
  146   
  147   		Object readResolve() {
  148   			return createSetter(clazz, propertyName);
  149   		}
  150   
  151   		public String toString() {
  152   			return "BasicSetter(" + clazz.getName() + '.' + propertyName + ')';
  153   		}
  154   	}
  155   
  156   	public static final class BasicGetter implements Getter {
  157   		private Class clazz;
  158   		private final transient Method method;
  159   		private final String propertyName;
  160   
  161   		private BasicGetter(Class clazz, Method method, String propertyName) {
  162   			this.clazz=clazz;
  163   			this.method=method;
  164   			this.propertyName=propertyName;
  165   		}
  166   
  167   		public Object get(Object target) throws HibernateException {
  168   			try {
  169   				return method.invoke(target, null);
  170   			}
  171   			catch (InvocationTargetException ite) {
  172   				throw new PropertyAccessException(
  173   						ite, 
  174   						"Exception occurred inside", 
  175   						false, 
  176   						clazz, 
  177   						propertyName
  178   					);
  179   			}
  180   			catch (IllegalAccessException iae) {
  181   				throw new PropertyAccessException(
  182   						iae, 
  183   						"IllegalAccessException occurred while calling", 
  184   						false, 
  185   						clazz, 
  186   						propertyName
  187   					);
  188   				//cannot occur
  189   			}
  190   			catch (IllegalArgumentException iae) {
  191   				log.error(
  192   						"IllegalArgumentException in class: " + clazz.getName() +
  193   						", getter method of property: " + propertyName
  194   					);
  195   				throw new PropertyAccessException(
  196   						iae, 
  197   						"IllegalArgumentException occurred calling", 
  198   						false, 
  199   						clazz, 
  200   						propertyName
  201   					);
  202   			}
  203   		}
  204   
  205   		public Object getForInsert(Object target, Map mergeMap, SessionImplementor session) {
  206   			return get( target );
  207   		}
  208   
  209   		public Class getReturnType() {
  210   			return method.getReturnType();
  211   		}
  212   
  213   		public Method getMethod() {
  214   			return method;
  215   		}
  216   
  217   		public String getMethodName() {
  218   			return method.getName();
  219   		}
  220   
  221   		public String toString() {
  222   			return "BasicGetter(" + clazz.getName() + '.' + propertyName + ')';
  223   		}
  224   		
  225   		Object readResolve() {
  226   			return createGetter(clazz, propertyName);
  227   		}
  228   	}
  229   
  230   
  231   	public Setter getSetter(Class theClass, String propertyName) 
  232   	throws PropertyNotFoundException {
  233   		return createSetter(theClass, propertyName);
  234   	}
  235   	
  236   	private static Setter createSetter(Class theClass, String propertyName) 
  237   	throws PropertyNotFoundException {
  238   		BasicSetter result = getSetterOrNull(theClass, propertyName);
  239   		if (result==null) {
  240   			throw new PropertyNotFoundException( 
  241   					"Could not find a setter for property " + 
  242   					propertyName + 
  243   					" in class " + 
  244   					theClass.getName() 
  245   				);
  246   		}
  247   		return result;
  248   	}
  249   
  250   	private static BasicSetter getSetterOrNull(Class theClass, String propertyName) {
  251   
  252   		if (theClass==Object.class || theClass==null) return null;
  253   
  254   		Method method = setterMethod(theClass, propertyName);
  255   
  256   		if (method!=null) {
  257   			if ( !ReflectHelper.isPublic(theClass, method) ) method.setAccessible(true);
  258   			return new BasicSetter(theClass, method, propertyName);
  259   		}
  260   		else {
  261   			BasicSetter setter = getSetterOrNull( theClass.getSuperclass(), propertyName );
  262   			if (setter==null) {
  263   				Class[] interfaces = theClass.getInterfaces();
  264   				for ( int i=0; setter==null && i<interfaces.length; i++ ) {
  265   					setter=getSetterOrNull( interfaces[i], propertyName );
  266   				}
  267   			}
  268   			return setter;
  269   		}
  270   
  271   	}
  272   
  273   	private static Method setterMethod(Class theClass, String propertyName) {
  274   
  275   		BasicGetter getter = getGetterOrNull(theClass, propertyName);
  276   		Class returnType = (getter==null) ? null : getter.getReturnType();
  277   
  278   		Method[] methods = theClass.getDeclaredMethods();
  279   		Method potentialSetter = null;
  280   		for (int i=0; i<methods.length; i++) {
  281   			String methodName = methods[i].getName();
  282   
  283   			if ( methods[i].getParameterTypes().length==1 && methodName.startsWith("set") ) {
  284   				String testStdMethod = Introspector.decapitalize( methodName.substring(3) );
  285   				String testOldMethod = methodName.substring(3);
  286   				if ( testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName) ) {
  287   					potentialSetter = methods[i];
  288   					if ( returnType==null || methods[i].getParameterTypes()[0].equals(returnType) ) {
  289   						return potentialSetter;
  290   					}
  291   				}
  292   			}
  293   		}
  294   		return potentialSetter;
  295   	}
  296   
  297   	public Getter getGetter(Class theClass, String propertyName) 
  298   	throws PropertyNotFoundException {
  299   		return createGetter(theClass, propertyName);
  300   	}
  301   	
  302   	public static Getter createGetter(Class theClass, String propertyName) 
  303   	throws PropertyNotFoundException {
  304   		BasicGetter result = getGetterOrNull(theClass, propertyName);
  305   		if (result==null) {
  306   			throw new PropertyNotFoundException( 
  307   					"Could not find a getter for " + 
  308   					propertyName + 
  309   					" in class " + 
  310   					theClass.getName() 
  311   			);
  312   		}
  313   		return result;
  314   
  315   	}
  316   
  317   	private static BasicGetter getGetterOrNull(Class theClass, String propertyName) {
  318   
  319   		if (theClass==Object.class || theClass==null) return null;
  320   
  321   		Method method = getterMethod(theClass, propertyName);
  322   
  323   		if (method!=null) {
  324   			if ( !ReflectHelper.isPublic(theClass, method) ) method.setAccessible(true);
  325   			return new BasicGetter(theClass, method, propertyName);
  326   		}
  327   		else {
  328   			BasicGetter getter = getGetterOrNull( theClass.getSuperclass(), propertyName );
  329   			if (getter==null) {
  330   				Class[] interfaces = theClass.getInterfaces();
  331   				for ( int i=0; getter==null && i<interfaces.length; i++ ) {
  332   					getter=getGetterOrNull( interfaces[i], propertyName );
  333   				}
  334   			}
  335   			return getter;
  336   		}
  337   	}
  338   
  339   	private static Method getterMethod(Class theClass, String propertyName) {
  340   
  341   		Method[] methods = theClass.getDeclaredMethods();
  342   		for (int i=0; i<methods.length; i++) {
  343   			// only carry on if the method has no parameters
  344   			if ( methods[i].getParameterTypes().length == 0 ) {
  345   				String methodName = methods[i].getName();
  346   
  347   				// try "get"
  348   				if ( methodName.startsWith("get") ) {
  349   					String testStdMethod = Introspector.decapitalize( methodName.substring(3) );
  350   					String testOldMethod = methodName.substring(3);
  351   					if ( testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName) ) {
  352   						return methods[i];
  353   					}
  354   
  355   				}
  356   
  357   				// if not "get", then try "is"
  358   				if ( methodName.startsWith("is") ) {
  359   					String testStdMethod = Introspector.decapitalize( methodName.substring(2) );
  360   					String testOldMethod = methodName.substring(2);
  361   					if ( testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName) ) {
  362   						return methods[i];
  363   					}
  364   				}
  365   			}
  366   		}
  367   		return null;
  368   	}
  369   
  370   }

Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » property » [javadoc | source]