- Timestamp:
- 06/28/13 11:56:03 (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
java/main/src/main/java/com/framsticks/params/ReflectionAccess.java
r86 r87 4 4 import java.lang.reflect.InvocationTargetException; 5 5 import java.lang.reflect.Method; 6 import java.util.Collections; 6 7 import java.util.HashMap; 7 8 import java.util.Map; 8 9 10 import javax.annotation.concurrent.Immutable; 11 9 12 import org.apache.log4j.Logger; 10 13 14 import com.framsticks.params.annotations.AutoAppendAnnotation; 11 15 import com.framsticks.util.FramsticksException; 16 import com.framsticks.util.lang.Pair; 12 17 13 18 import static com.framsticks.util.lang.Containers.*; … … 22 27 */ 23 28 public class ReflectionAccess extends SimpleAbstractAccess { 24 private final static Logger log = Logger.getLogger(ReflectionAccess.class 25 .getName()); 29 private final static Logger log = Logger.getLogger(ReflectionAccess.class.getName()); 26 30 27 31 protected final Class<?> reflectedClass; 32 protected final Backend backend; 33 28 34 private Object object; 29 35 30 31 protected interface ReflectedSetter { 32 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException; 33 } 34 35 protected interface ReflectedGetter { 36 public abstract <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException; 37 } 38 39 protected static class ReflectedValueParam { 40 public ReflectedSetter setter; 41 public ReflectedGetter getter; 42 } 43 44 protected final Map<ValueParam, ReflectedValueParam> reflectedValueParams = new HashMap<>(); 36 @Immutable 37 public static class Backend { 38 39 protected static Map<Pair<Class<?>, FramsClass>, Backend> synchronizedCache = Collections.synchronizedMap(new HashMap<Pair<Class<?>, FramsClass>, Backend>()); 40 41 public static class ReflectedValueParam { 42 public ReflectedSetter setter; 43 public ReflectedGetter getter; 44 } 45 46 public interface ReflectedSetter { 47 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException; 48 } 49 50 public interface ReflectedGetter { 51 public abstract <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException; 52 } 53 54 protected final Map<ValueParam, ReflectedValueParam> params; 55 protected final Map<Class<?>, Method> autoAppendMethods; 56 57 /** 58 * @param params 59 */ 60 public Backend(Map<ValueParam, ReflectedValueParam> params, Map<Class<?>, Method> autoAppendMethods) { 61 // this.params = Collections.unmodifiableMap(params); 62 this.params = params; 63 this.autoAppendMethods = autoAppendMethods; 64 } 65 66 public static Backend getOrCreateFor(Class<?> reflectedClass, FramsClass framsClass) { 67 68 Pair<Class<?>, FramsClass> id = new Pair<Class<?>, FramsClass>(reflectedClass, framsClass); 69 Backend backend = synchronizedCache.get(id); 70 if (backend != null) { 71 return backend; 72 } 73 74 log.debug("constructing backend for " + id); 75 final Map<ValueParam, ReflectedValueParam> params = new HashMap<>(); 76 77 Map<String, ParamCandidate> candidates = ParamCandidate.getAllCandidates(reflectedClass); 78 79 try { 80 for (final ValueParam vp : filterInstanceof(framsClass.getParamEntries(), ValueParam.class)) { 81 if (!candidates.containsKey(vp.getId())) { 82 throw new ConstructionException().msg("missing candidate for param").arg("param", vp); 83 } 84 ParamCandidate pc = candidates.get(vp.getId()); 85 if (pc.isReadOnly() && !vp.hasFlag(Flags.READONLY)) { 86 throw new ConstructionException().msg("readonly state conflict").arg("param", vp); 87 } 88 if (!typeMatch(pc.getRawType(), vp.getStorageType())) { 89 throw new ConstructionException().msg("types mismatch for param").arg("param", vp).arg("candidate", pc.getType()).arg("storage", vp.getStorageType()); 90 } 91 92 ReflectedValueParam rvp = new ReflectedValueParam(); 93 params.put(vp, rvp); 94 final boolean primitive = pc.isPrimitive(); 95 if (pc.getField() != null) { 96 final Field f = pc.getField(); 97 rvp.getter = new ReflectedGetter() { 98 @Override 99 public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException { 100 return type.cast(f.get(object)); 101 } 102 }; 103 if (!pc.isFinal()) { 104 rvp.setter = new ReflectedSetter() { 105 @Override 106 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException { 107 if (value == null && primitive) { 108 throw new FramsticksException().msg("setting null to primitive value"); 109 } 110 f.set(object, value); 111 } 112 }; 113 } 114 } else { 115 final Method g = pc.getGetter(); 116 117 rvp.getter = new ReflectedGetter() { 118 @Override 119 public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { 120 return type.cast(g.invoke(object)); 121 } 122 }; 123 124 if (!pc.isFinal()) { 125 final Method s = pc.getSetter(); 126 rvp.setter = new ReflectedSetter() { 127 @Override 128 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { 129 if (value == null && primitive) { 130 throw new FramsticksException().msg("setting null to primitive value"); 131 } 132 s.invoke(object, value); 133 } 134 }; 135 } 136 } 137 } 138 } catch (ConstructionException e) { 139 throw e.arg("java class", reflectedClass).arg("framsClass", framsClass); 140 } 141 142 Map<Class<?>, Method> autoAppendMethods = new HashMap<>(); 143 144 Class<?> javaClass = reflectedClass; 145 while (javaClass != null) { 146 147 for (Method m : javaClass.getDeclaredMethods()) { 148 AutoAppendAnnotation a = m.getAnnotation(AutoAppendAnnotation.class); 149 if (a == null) { 150 continue; 151 } 152 Class<?>[] args = m.getParameterTypes(); 153 if (args.length != 1) { 154 throw new ConstructionException().msg("invalid number of arguments in AutoAppend marked method").arg("method", m).arg("arguments", args.length); 155 } 156 autoAppendMethods.put(args[0], m); 157 } 158 159 javaClass = javaClass.getSuperclass(); 160 } 161 162 backend = new Backend(params, autoAppendMethods); 163 synchronizedCache.put(id, backend); 164 return backend; 165 } 166 167 } 45 168 46 169 public ReflectionAccess(Class<?> reflectedClass) throws ConstructionException { 47 this(reflectedClass, FramsClass Builder.buildForClass(reflectedClass));170 this(reflectedClass, FramsClass.build().forClass(reflectedClass)); 48 171 } 49 172 … … 68 191 69 192 public ReflectionAccess(Class<?> reflectedClass, FramsClass framsClass) throws ConstructionException { 193 super(framsClass); 70 194 this.reflectedClass = reflectedClass; 71 setFramsClass(framsClass); 72 73 Map<String, ParamCandidate> candidates = ParamCandidate.getAllCandidates(reflectedClass); 74 75 try { 76 for (final ValueParam vp : filterInstanceof(framsClass.getParamEntries(), ValueParam.class)) { 77 if (!candidates.containsKey(vp.getId())) { 78 throw new ConstructionException().msg("missing candidate for param").arg("param", vp); 79 } 80 ParamCandidate pc = candidates.get(vp.getId()); 81 if (pc.isReadOnly() && !vp.hasFlag(Flags.READONLY)) { 82 throw new ConstructionException().msg("readonly state conflict").arg("param", vp); 83 } 84 if (!typeMatch(pc.getRawType(), vp.getStorageType())) { 85 throw new ConstructionException().msg("types mismatch for param").arg("param", vp).arg("candidate", pc.getType()).arg("storage", vp.getStorageType()); 86 } 87 88 ReflectedValueParam rvp = new ReflectedValueParam(); 89 reflectedValueParams.put(vp, rvp); 90 final boolean primitive = pc.isPrimitive(); 91 if (pc.getField() != null) { 92 final Field f = pc.getField(); 93 rvp.getter = new ReflectedGetter() { 94 @Override 95 public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException { 96 return type.cast(f.get(object)); 97 } 98 }; 99 if (!pc.isFinal()) { 100 rvp.setter = new ReflectedSetter() { 101 @Override 102 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException { 103 if (value == null && primitive) { 104 throw new FramsticksException().msg("setting null to primitive value"); 105 } 106 f.set(object, value); 107 } 108 }; 109 } 110 } else { 111 final Method g = pc.getGetter(); 112 113 rvp.getter = new ReflectedGetter() { 114 @Override 115 public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { 116 return type.cast(g.invoke(object)); 117 } 118 }; 119 120 if (!pc.isFinal()) { 121 final Method s = pc.getSetter(); 122 rvp.setter = new ReflectedSetter() { 123 @Override 124 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { 125 if (value == null && primitive) { 126 throw new FramsticksException().msg("setting null to primitive value"); 127 } 128 s.invoke(object, value); 129 } 130 }; 131 } 132 } 133 } 134 } catch (ConstructionException e) { 135 throw e.arg("java class", reflectedClass).arg("framsClass", framsClass); 136 } 195 this.backend = Backend.getOrCreateFor(reflectedClass, framsClass); 196 // log.info("created ReflectionAccess " + this); 137 197 } 138 198 … … 149 209 } 150 210 151 return reflectedValueParams.get(param).getter.get(object, type);211 return backend.params.get(param).getter.get(object, type); 152 212 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 153 213 throw new FramsticksException().msg("failed to get").cause(e); … … 169 229 throw new FramsticksException().msg("no object set"); 170 230 } 171 ReflectedSetter s = reflectedValueParams.get(param).setter;231 Backend.ReflectedSetter s = backend.params.get(param).setter; 172 232 if (s == null) { 173 233 throw new FramsticksException().msg("trying to set final"); … … 238 298 } 239 299 240 241 300 @Override 242 301 public ReflectionAccess cloneAccess() throws ConstructionException { … … 265 324 } 266 325 326 @Override 327 public boolean tryAutoAppend(Object value) { 328 assert object != null; 329 for (Map.Entry<Class<?>, Method> a : backend.autoAppendMethods.entrySet()) { 330 if (a.getKey().isAssignableFrom(value.getClass())) { 331 try { 332 a.getValue().invoke(object, value); 333 return true; 334 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 335 throw new FramsticksException().msg("failed to auto append").cause(e).arg("value", value).arg("into object", object).arg("with method", a.getValue()); 336 } 337 } 338 } 339 return false; 340 } 267 341 } 268 342
Note: See TracChangeset
for help on using the changeset viewer.