001/* 002 * Copyright (c) 2004-2012, Willem Cazander 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, are permitted provided 006 * that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, this list of conditions and the 009 * following disclaimer. 010 * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 011 * the following disclaimer in the documentation and/or other materials provided with the distribution. 012 * 013 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 014 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 015 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 016 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 017 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 018 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 019 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 020 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 021 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 022 */ 023 024package org.x4o.xml.impl; 025 026import java.io.Serializable; 027import java.lang.reflect.Method; 028import java.util.Iterator; 029import java.util.Locale; 030import java.util.Map; 031import java.util.logging.Logger; 032 033import org.x4o.xml.conv.DefaultObjectConverterProvider; 034import org.x4o.xml.conv.ObjectConverter; 035import org.x4o.xml.conv.ObjectConverterException; 036import org.x4o.xml.element.ElementObjectPropertyValue; 037import org.x4o.xml.element.ElementObjectPropertyValueException; 038 039/** 040 * An DefaultElementObjectPropertyValue which does does get/set operations on pojo beans. 041 * 042 * @author Willem Cazander 043 * @version 1.0 Feb 16, 2007 044 */ 045public class DefaultElementObjectPropertyValue implements ElementObjectPropertyValue,Serializable { 046 047 private static final long serialVersionUID = 1L; 048 049 private Logger logger = Logger.getLogger(DefaultElementObjectPropertyValue.class.getName()); 050 051 private Method findMethod(Object object,String parameterName,Object parameter) { 052 053 // Get class but can be null. 054 Class<?> parameterClass = null; 055 if(parameter!=null) { 056 parameterClass=parameter.getClass(); 057 } 058 logger.finer("Trying value: pn="+parameterName+" o="+object+" p="+parameter+"("+parameterClass+")"); 059 String parameterNameSet = "set"+parameterName; 060 Method[] methodes = object.getClass().getMethods(); 061 Method lastMethodFall = null; 062 for (int i=0;i<methodes.length;i++) { 063 Method method = methodes[i]; 064 Class<?>[] types = method.getParameterTypes(); 065 if (types.length == 0) { 066 continue; 067 } 068 if (types.length > 1) { 069 continue; 070 } 071 if (method.getName().equalsIgnoreCase(parameterNameSet)) { 072 lastMethodFall = method; 073 if (parameterClass!=null) { 074 // Check for class based parameters. 075 if (types[0].isAssignableFrom(parameterClass)) { 076 logger.finest("Found method type: "+method.getParameterTypes()[0]+" for parameter: "+parameterName); 077 return method; 078 } 079 // Check the native parameter types. 080 if (parameterClass.isAssignableFrom(Boolean.class) && types[0].isAssignableFrom(Boolean.TYPE) ) { 081 return method; 082 } 083 if (parameterClass.isAssignableFrom(Integer.class) && types[0].isAssignableFrom(Integer.TYPE) ) { 084 return method; 085 } 086 if (parameterClass.isAssignableFrom(Long.class) && types[0].isAssignableFrom(Long.TYPE) ) { 087 return method; 088 } 089 if (parameterClass.isAssignableFrom(Double.class) && types[0].isAssignableFrom(Double.TYPE) ) { 090 return method; 091 } 092 if (parameterClass.isAssignableFrom(Float.class) && types[0].isAssignableFrom(Float.TYPE) ) { 093 return method; 094 } 095 if (parameterClass.isAssignableFrom(Byte.class) && types[0].isAssignableFrom(Byte.TYPE) ) { 096 return method; 097 } 098 if (parameterClass.isAssignableFrom(Character.class) && types[0].isAssignableFrom(Character.TYPE) ) { 099 return method; 100 } 101 } 102 } 103 } 104 return lastMethodFall; 105 } 106 107 /** 108 * TODO: this function is not completed !! 109 * 110 * 111 * 112 * @param object 113 * @param parameterName 114 * @param parameter 115 * @throws ElementParameterException 116 * @throws ElementObjectPropertyValueException 117 */ 118 public void setProperty(Object object,String parameterName,Object parameter) throws ElementObjectPropertyValueException { 119 120 // find the method for the parameter 121 Method lastMethod = findMethod(object,parameterName,parameter); 122 if (lastMethod==null) { 123 logger.finest("No method found, aborting parameter: "+parameterName); 124 return; 125 } 126 127 // Special case for null value. 128 if (parameter==null) { 129 logger.finest("Found parameter is null Setting method: "+lastMethod.getParameterTypes()[0]+" for parameter: "+parameterName); 130 try { 131 lastMethod.invoke(object,new Object[]{parameter}); 132 return; 133 } catch (Exception e) { 134 throw new ElementObjectPropertyValueException(e.getMessage(),e); 135 } 136 } 137 138 // Invoke for class based parameters 139 if (lastMethod.getParameterTypes()[0].isAssignableFrom(parameter.getClass())) { 140 logger.finest("Found parameter type: "+lastMethod.getParameterTypes()[0]+" for parameter: "+parameterName+" setting value: "+parameter); 141 try { 142 lastMethod.invoke(object,new Object[]{parameter}); 143 return; 144 } catch (Exception e) { 145 throw new ElementObjectPropertyValueException(e.getMessage(),e); 146 } 147 } 148 149 // Invoke for native based types 150 151 152 // not found 2sec try 153 logger.finest("No corresoning class is found, trying convert manualy"); 154 155 // special case for object. 156 if (lastMethod.getParameterTypes()[0].equals(Object.class) ) { 157 logger.finest("Set Special object value: "+parameterName+" parm2: "+parameter+" on2="+lastMethod.getName()+" with="+object); 158 try { 159 lastMethod.invoke(object,new Object[]{parameter}); 160 } catch (Exception e) { 161 throw new ElementObjectPropertyValueException(e.getMessage(),e); 162 } 163 return; 164 } 165 166 // all below creates from string 167 if (parameter.toString().length()==0) { 168 return; // can't set value from string with empty size. 169 } 170 171 // 172 // JAVA OBJECT TYPES: 173 // 174 Object parameter2 = null; 175 176 try { 177 DefaultObjectConverterProvider convProvider = new DefaultObjectConverterProvider(); 178 convProvider.addDefaults(); 179 ObjectConverter conv = convProvider.getObjectConverterForClass(lastMethod.getParameterTypes()[0]); 180 if (conv!=null) { 181 parameter2 = conv.convertTo(parameter.toString(), Locale.getDefault()); 182 } 183 184 /* 185 * JAVA NATIVE TYPES: 186 * 187 * TYPE: Size in bits: 188 * boolean 8, unsigned 189 * byte 8 190 * char 16, unsigned 191 * short 16 192 * int 32 193 * long 64 194 * float 32 195 * double 64 196 * void n/a 197 */ 198 if (lastMethod.getParameterTypes()[0].isAssignableFrom(Boolean.TYPE) ) { 199 conv = convProvider.getObjectConverterForClass(Boolean.class); 200 parameter2 = conv.convertTo(parameter.toString(), Locale.getDefault()); 201 } 202 if (lastMethod.getParameterTypes()[0].isAssignableFrom(Integer.TYPE) ) { 203 conv = convProvider.getObjectConverterForClass(Integer.class); 204 parameter2 = conv.convertTo(parameter.toString(), Locale.getDefault()); 205 } 206 if (lastMethod.getParameterTypes()[0].isAssignableFrom(Long.TYPE) ) { 207 conv = convProvider.getObjectConverterForClass(Long.class); 208 parameter2 = conv.convertTo(parameter.toString(), Locale.getDefault()); 209 } 210 if (lastMethod.getParameterTypes()[0].isAssignableFrom(Double.TYPE) ) { 211 conv = convProvider.getObjectConverterForClass(Double.class); 212 parameter2 = conv.convertTo(parameter.toString(), Locale.getDefault()); 213 } 214 if (lastMethod.getParameterTypes()[0].isAssignableFrom(Float.TYPE) ) { 215 conv = convProvider.getObjectConverterForClass(Float.class); 216 parameter2 = conv.convertTo(parameter.toString(), Locale.getDefault()); 217 } 218 if (lastMethod.getParameterTypes()[0].isAssignableFrom(Byte.TYPE) ) { 219 conv = convProvider.getObjectConverterForClass(Byte.class); 220 parameter2 = conv.convertTo(parameter.toString(), Locale.getDefault()); 221 } 222 if (lastMethod.getParameterTypes()[0].isAssignableFrom(Character.TYPE) ) { 223 conv = convProvider.getObjectConverterForClass(Character.class); 224 parameter2 = conv.convertTo(parameter.toString(), Locale.getDefault()); 225 } 226 227 } catch (ObjectConverterException oce) { 228 throw new ElementObjectPropertyValueException(oce.getMessage(),oce); 229 } 230 231 if (parameter2==null) { 232 throw new ElementObjectPropertyValueException("Could not convert to type for parameter: '"+parameterName+"' value: '"+parameter+"'"); 233 } 234 235 logger.finest("Set value: "+parameterName+" parm2: "+parameter2+" on2="+lastMethod.getName()+" with="+object); 236 try { 237 lastMethod.invoke(object,new Object[]{parameter2}); 238 } catch (Exception e) { 239 throw new ElementObjectPropertyValueException(e.getMessage(),e); 240 } 241 } 242 243 /** 244 * Gets the property of an bean. 245 * 246 * @param object The object to get from. 247 * @param parameterName The parameter name of the property to get. 248 * @throws ElementParameterException 249 * @throws ElementObjectPropertyValueException 250 */ 251 public Object getProperty(Object object,String parameterName) throws ElementObjectPropertyValueException { 252 253 if (object==null) { 254 throw new NullPointerException("Can't get property of null object."); 255 } 256 if (parameterName==null) { 257 throw new NullPointerException("Can't get property is the name is null."); 258 } 259 260 Logger logger = Logger.getLogger(DefaultElementObjectPropertyValue.class.getName()); 261 262 String propRest = null; 263 int index = parameterName.indexOf("."); 264 if(index>0) { 265 propRest = parameterName.substring(index+1); 266 parameterName = parameterName.substring(0,index); 267 logger.finest("slit property into: '"+propRest+"' and '"+parameterName+"'"); 268 } 269 270 logger.finer("Trying value: pn="+parameterName+" o="+object); 271 String parameterNameSet = "get"+parameterName; 272 Method[] methodes = object.getClass().getMethods(); 273 Method lastMethod = null; 274 275 // a bit hackie 276 for(int i=0;i<methodes.length;i++) { 277 Method method = methodes[i]; 278 if(method.getName().equalsIgnoreCase(parameterNameSet)) { 279 logger.finest("Found method: "+method.getName()); 280 lastMethod = method; 281 break; 282 } 283 } 284 285 if (lastMethod==null) { 286 for(int i=0;i<methodes.length;i++) { 287 Method method = methodes[i]; 288 if(method.getName().equalsIgnoreCase("is"+parameterName)) { 289 logger.finest("Found is method: "+method.getName()); 290 lastMethod = method; 291 break; 292 } 293 if(method.getName().equalsIgnoreCase("has"+parameterName)) { 294 logger.finest("Found has method: "+method.getName()); 295 lastMethod = method; 296 break; 297 } 298 } 299 } 300 301 if (lastMethod==null) { 302 throw new ElementObjectPropertyValueException("Could not find method for parameter: '"+parameterName+"' object: '"+object+"'"); 303 } 304 305 Object result = null; 306 try { 307 result = lastMethod.invoke(object); 308 } catch (Exception e) { 309 throw new ElementObjectPropertyValueException(e.getMessage(),e); 310 } 311 312 if (propRest!=null) { 313 if (result==null) { 314 return null; // no need to go deeper into a null value. 315 } 316 // recursif function: 317 return getProperty(result,propRest); 318 } 319 320 return result; 321 } 322 323 /** 324 * @see org.x4o.xml.element.ElementObjectPropertyValue#setPropertyMap(java.lang.Object, java.util.Map) 325 */ 326 public void setPropertyMap(Object object, Map<String, Object> attributes) throws ElementObjectPropertyValueException { 327 Iterator<String> keyIterator = attributes.keySet().iterator(); 328 while(keyIterator.hasNext()) { 329 String key = keyIterator.next(); 330 setProperty(object,key,attributes.get(key)); 331 } 332 } 333}