1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002,2008 Oracle. All rights reserved. 5 * 6 * $Id: ReflectionAccessor.java,v 1.1 2008/02/07 17:12:27 mark Exp $ 7 */ 8 9package com.sleepycat.persist.impl; 10 11import java.lang.reflect.AccessibleObject; 12import java.lang.reflect.Array; 13import java.lang.reflect.Constructor; 14import java.lang.reflect.Field; 15import java.lang.reflect.InvocationTargetException; 16import java.lang.reflect.Modifier; 17import java.util.List; 18 19/** 20 * Implements Accessor using reflection. 21 * 22 * @author Mark Hayes 23 */ 24class ReflectionAccessor implements Accessor { 25 26 private static final FieldAccess[] EMPTY_KEYS = {}; 27 28 private Class type; 29 private Accessor superAccessor; 30 private Constructor constructor; 31 private FieldAccess priKey; 32 private FieldAccess[] secKeys; 33 private FieldAccess[] nonKeys; 34 35 private ReflectionAccessor(Class type, Accessor superAccessor) { 36 this.type = type; 37 this.superAccessor = superAccessor; 38 try { 39 constructor = type.getDeclaredConstructor(); 40 } catch (NoSuchMethodException e) { 41 throw new IllegalStateException(type.getName()); 42 } 43 if (!Modifier.isPublic(constructor.getModifiers())) { 44 setAccessible(constructor, type.getName() + "()"); 45 } 46 } 47 48 ReflectionAccessor(Catalog catalog, 49 Class type, 50 Accessor superAccessor, 51 FieldInfo priKeyField, 52 List<FieldInfo> secKeyFields, 53 List<FieldInfo> nonKeyFields) { 54 this(type, superAccessor); 55 if (priKeyField != null) { 56 priKey = getField(catalog, priKeyField, true, false); 57 } else { 58 priKey = null; 59 } 60 if (secKeyFields.size() > 0) { 61 secKeys = getFields(catalog, secKeyFields, false, false); 62 } else { 63 secKeys = EMPTY_KEYS; 64 } 65 if (nonKeyFields.size() > 0) { 66 nonKeys = getFields(catalog, nonKeyFields, false, false); 67 } else { 68 nonKeys = EMPTY_KEYS; 69 } 70 } 71 72 ReflectionAccessor(Catalog catalog, 73 Class type, 74 List<FieldInfo> fieldInfos) { 75 this(type, null); 76 priKey = null; 77 secKeys = EMPTY_KEYS; 78 nonKeys = getFields(catalog, fieldInfos, true, true); 79 } 80 81 private FieldAccess[] getFields(Catalog catalog, 82 List<FieldInfo> fieldInfos, 83 boolean isRequiredKeyField, 84 boolean isCompositeKey) { 85 int index = 0; 86 FieldAccess[] fields = new FieldAccess[fieldInfos.size()]; 87 for (FieldInfo info : fieldInfos) { 88 fields[index] = getField 89 (catalog, info, isRequiredKeyField, isCompositeKey); 90 index += 1; 91 } 92 return fields; 93 } 94 95 private FieldAccess getField(Catalog catalog, 96 FieldInfo fieldInfo, 97 boolean isRequiredKeyField, 98 boolean isCompositeKey) { 99 Field field; 100 try { 101 field = type.getDeclaredField(fieldInfo.getName()); 102 } catch (NoSuchFieldException e) { 103 throw new IllegalStateException(e); 104 } 105 if (!Modifier.isPublic(field.getModifiers())) { 106 setAccessible(field, field.getName()); 107 } 108 Class fieldCls = field.getType(); 109 if (fieldCls.isPrimitive()) { 110 assert SimpleCatalog.isSimpleType(fieldCls); 111 return new PrimitiveAccess 112 (field, SimpleCatalog.getSimpleFormat(fieldCls)); 113 } else if (isRequiredKeyField) { 114 Format format = catalog.getFormat(fieldCls); 115 if (isCompositeKey && !SimpleCatalog.isSimpleType(fieldCls)) { 116 throw new IllegalArgumentException 117 ("Composite key class has non-simple type field: " + 118 type.getName() + '.' + field.getName()); 119 } 120 return new KeyObjectAccess(field, format); 121 } else { 122 return new ObjectAccess(field); 123 } 124 } 125 126 private void setAccessible(AccessibleObject object, String memberName) { 127 try { 128 object.setAccessible(true); 129 } catch (SecurityException e) { 130 throw new IllegalStateException 131 ("Unable to access non-public member: " + 132 type.getName() + '.' + memberName + 133 ". Please configure the Java Security Manager setting: " + 134 " ReflectPermission suppressAccessChecks", e); 135 } 136 } 137 138 public Object newInstance() { 139 try { 140 return constructor.newInstance(); 141 } catch (IllegalAccessException e) { 142 throw new IllegalStateException(e); 143 } catch (InstantiationException e) { 144 throw new IllegalStateException(e); 145 } catch (InvocationTargetException e) { 146 throw new IllegalStateException(e); 147 } 148 } 149 150 public Object newArray(int len) { 151 return Array.newInstance(type, len); 152 } 153 154 public boolean isPriKeyFieldNullOrZero(Object o) { 155 try { 156 if (priKey != null) { 157 return priKey.isNullOrZero(o); 158 } else if (superAccessor != null) { 159 return superAccessor.isPriKeyFieldNullOrZero(o); 160 } else { 161 throw new IllegalStateException("No primary key field"); 162 } 163 } catch (IllegalAccessException e) { 164 throw new IllegalStateException(e); 165 } 166 } 167 168 public void writePriKeyField(Object o, EntityOutput output) { 169 try { 170 if (priKey != null) { 171 priKey.write(o, output); 172 } else if (superAccessor != null) { 173 superAccessor.writePriKeyField(o, output); 174 } else { 175 throw new IllegalStateException("No primary key field"); 176 } 177 } catch (IllegalAccessException e) { 178 throw new IllegalStateException(e); 179 } 180 } 181 182 public void readPriKeyField(Object o, EntityInput input) { 183 try { 184 if (priKey != null) { 185 priKey.read(o, input); 186 } else if (superAccessor != null) { 187 superAccessor.readPriKeyField(o, input); 188 } else { 189 throw new IllegalStateException("No primary key field"); 190 } 191 } catch (IllegalAccessException e) { 192 throw new IllegalStateException(e); 193 } 194 } 195 196 public void writeSecKeyFields(Object o, EntityOutput output) { 197 try { 198 if (priKey != null && !priKey.isPrimitive) { 199 output.registerPriKeyObject(priKey.field.get(o)); 200 } 201 if (superAccessor != null) { 202 superAccessor.writeSecKeyFields(o, output); 203 } 204 for (int i = 0; i < secKeys.length; i += 1) { 205 secKeys[i].write(o, output); 206 } 207 } catch (IllegalAccessException e) { 208 throw new IllegalStateException(e); 209 } 210 } 211 212 public void readSecKeyFields(Object o, 213 EntityInput input, 214 int startField, 215 int endField, 216 int superLevel) { 217 try { 218 if (priKey != null && !priKey.isPrimitive) { 219 input.registerPriKeyObject(priKey.field.get(o)); 220 } 221 if (superLevel != 0 && superAccessor != null) { 222 superAccessor.readSecKeyFields 223 (o, input, startField, endField, superLevel - 1); 224 } else { 225 if (superLevel > 0) { 226 throw new IllegalStateException 227 ("Superclass does not exist"); 228 } 229 } 230 if (superLevel <= 0) { 231 for (int i = startField; 232 i <= endField && i < secKeys.length; 233 i += 1) { 234 secKeys[i].read(o, input); 235 } 236 } 237 } catch (IllegalAccessException e) { 238 throw new IllegalStateException(e); 239 } 240 } 241 242 public void writeNonKeyFields(Object o, EntityOutput output) { 243 try { 244 if (superAccessor != null) { 245 superAccessor.writeNonKeyFields(o, output); 246 } 247 for (int i = 0; i < nonKeys.length; i += 1) { 248 nonKeys[i].write(o, output); 249 } 250 } catch (IllegalAccessException e) { 251 throw new IllegalStateException(e); 252 } 253 } 254 255 public void readNonKeyFields(Object o, 256 EntityInput input, 257 int startField, 258 int endField, 259 int superLevel) { 260 try { 261 if (superLevel != 0 && superAccessor != null) { 262 superAccessor.readNonKeyFields 263 (o, input, startField, endField, superLevel - 1); 264 } else { 265 if (superLevel > 0) { 266 throw new IllegalStateException 267 ("Superclass does not exist"); 268 } 269 } 270 if (superLevel <= 0) { 271 for (int i = startField; 272 i <= endField && i < nonKeys.length; 273 i += 1) { 274 nonKeys[i].read(o, input); 275 } 276 } 277 } catch (IllegalAccessException e) { 278 throw new IllegalStateException(e); 279 } 280 } 281 282 public Object getField(Object o, 283 int field, 284 int superLevel, 285 boolean isSecField) { 286 if (superLevel > 0) { 287 return superAccessor.getField 288 (o, field, superLevel - 1, isSecField); 289 } 290 try { 291 Field fld = 292 isSecField ? secKeys[field].field : nonKeys[field].field; 293 return fld.get(o); 294 } catch (IllegalAccessException e) { 295 throw new IllegalStateException(e); 296 } 297 } 298 299 public void setField(Object o, 300 int field, 301 int superLevel, 302 boolean isSecField, 303 Object value) { 304 if (superLevel > 0) { 305 superAccessor.setField 306 (o, field, superLevel - 1, isSecField, value); 307 return; 308 } 309 try { 310 Field fld = 311 isSecField ? secKeys[field].field : nonKeys[field].field; 312 fld.set(o, value); 313 } catch (IllegalAccessException e) { 314 throw new IllegalStateException(e); 315 } 316 } 317 318 /** 319 * Abstract base class for field access classes. 320 */ 321 private static abstract class FieldAccess { 322 323 Field field; 324 boolean isPrimitive; 325 326 FieldAccess(Field field) { 327 this.field = field; 328 isPrimitive = field.getType().isPrimitive(); 329 } 330 331 /** 332 * Writes a field. 333 */ 334 abstract void write(Object o, EntityOutput out) 335 throws IllegalAccessException; 336 337 /** 338 * Reads a field. 339 */ 340 abstract void read(Object o, EntityInput in) 341 throws IllegalAccessException; 342 343 /** 344 * Returns whether a field is null (for reference types) or zero (for 345 * primitive integer types). This implementation handles the reference 346 * types. 347 */ 348 boolean isNullOrZero(Object o) 349 throws IllegalAccessException { 350 351 return field.get(o) == null; 352 } 353 } 354 355 /** 356 * Access for fields with object types. 357 */ 358 private static class ObjectAccess extends FieldAccess { 359 360 ObjectAccess(Field field) { 361 super(field); 362 } 363 364 @Override 365 void write(Object o, EntityOutput out) 366 throws IllegalAccessException { 367 368 out.writeObject(field.get(o), null); 369 } 370 371 @Override 372 void read(Object o, EntityInput in) 373 throws IllegalAccessException { 374 375 field.set(o, in.readObject()); 376 } 377 } 378 379 /** 380 * Access for primary key fields and composite key fields with object 381 * types. 382 */ 383 private static class KeyObjectAccess extends FieldAccess { 384 385 private Format format; 386 387 KeyObjectAccess(Field field, Format format) { 388 super(field); 389 this.format = format; 390 } 391 392 @Override 393 void write(Object o, EntityOutput out) 394 throws IllegalAccessException { 395 396 out.writeKeyObject(field.get(o), format); 397 } 398 399 @Override 400 void read(Object o, EntityInput in) 401 throws IllegalAccessException { 402 403 field.set(o, in.readKeyObject(format)); 404 } 405 } 406 407 /** 408 * Access for fields with primitive types. 409 */ 410 private static class PrimitiveAccess extends FieldAccess { 411 412 private SimpleFormat format; 413 414 PrimitiveAccess(Field field, SimpleFormat format) { 415 super(field); 416 this.format = format; 417 } 418 419 @Override 420 void write(Object o, EntityOutput out) 421 throws IllegalAccessException { 422 423 format.writePrimitiveField(o, out, field); 424 } 425 426 @Override 427 void read(Object o, EntityInput in) 428 throws IllegalAccessException { 429 430 format.readPrimitiveField(o, in, field); 431 } 432 433 @Override 434 boolean isNullOrZero(Object o) 435 throws IllegalAccessException { 436 437 return field.getLong(o) == 0; 438 } 439 } 440} 441