- Timestamp:
- 07/14/13 23:20:04 (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
java/main/src/main/java/com/framsticks/params/ReflectionAccess.java
r100 r101 1 1 package com.framsticks.params; 2 2 3 import java.lang.reflect.Field;4 3 import java.lang.reflect.InvocationTargetException; 5 4 import java.lang.reflect.Method; 6 import java.util.ArrayList; 7 import java.util.Collections; 8 import java.util.Comparator; 9 import java.util.HashMap; 10 import java.util.IdentityHashMap; 11 import java.util.List; 12 import java.util.Map; 13 14 import javax.annotation.concurrent.Immutable; 5 15 6 16 7 import org.apache.logging.log4j.Logger; 17 8 import org.apache.logging.log4j.LogManager; 18 9 19 import com.framsticks.params.annotations.AutoAppendAnnotation;20 10 import com.framsticks.params.types.EventParam; 21 11 import com.framsticks.params.types.ProcedureParam; 22 12 import com.framsticks.util.FramsticksException; 23 import com.framsticks.util.lang.Pair;24 13 25 14 import static com.framsticks.util.lang.Containers.*; … … 37 26 38 27 protected final Class<?> javaClass; 39 protected final Backend backend;28 protected final ReflectionAccessBackend backend; 40 29 41 30 private Object object; 42 43 @Immutable44 public static class Backend {45 46 protected static final Map<Pair<Class<?>, FramsClass>, Backend> synchronizedCache = Collections.synchronizedMap(new HashMap<Pair<Class<?>, FramsClass>, Backend>());47 48 49 public interface ReflectedGetter {50 public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;51 }52 53 public interface ReflectedSetter {54 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;55 }56 57 public interface ReflectedCaller {58 public Object call(Object object, Object[] arguments) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;59 }60 61 public interface ReflectedAdder{62 public void reg(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;63 }64 65 public interface ReflectedRemover{66 public void regRemove(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;67 }68 69 protected final Map<ValueParam, ReflectedSetter> setters = new IdentityHashMap<>();70 protected final Map<ValueParam, ReflectedGetter> getters = new IdentityHashMap<>();71 protected final Map<ProcedureParam, ReflectedCaller> callers = new IdentityHashMap<>();72 protected final Map<EventParam, ReflectedAdder> adders = new IdentityHashMap<>();73 protected final Map<EventParam, ReflectedRemover> removers = new IdentityHashMap<>();74 75 protected final List<Method> autoAppendMethods = new ArrayList<>();76 77 /**78 * @param params79 */80 public Backend() {81 }82 83 public static Backend getOrCreateFor(Class<?> reflectedClass, FramsClass framsClass) {84 85 Pair<Class<?>, FramsClass> id = new Pair<Class<?>, FramsClass>(reflectedClass, framsClass);86 Backend backend = synchronizedCache.get(id);87 if (backend != null) {88 return backend;89 }90 91 log.debug("constructing backend for {}", id);92 backend = new Backend();93 94 Map<String, ParamCandidate> candidates = ParamCandidate.getAllCandidates(reflectedClass).getCandidates();95 96 try {97 for (final ProcedureParam pp : filterInstanceof(framsClass.getParamEntries(), ProcedureParam.class)) {98 if (!candidates.containsKey(pp.getId())) {99 log.trace("java class does implement method {}", pp);100 continue;101 }102 ParamCandidate pc = candidates.get(pp.getId());103 final Method method = pc.getCaller();104 105 backend.callers.put(pp, new ReflectedCaller() {106 107 @Override108 public Object call(Object object, Object[] arguments) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {109 return method.invoke(object, arguments);110 }111 });112 113 }114 115 for (final EventParam ep : filterInstanceof(framsClass.getParamEntries(), EventParam.class)) {116 if (!candidates.containsKey(ep.getId())) {117 log.trace("java class does not implement the event param {}", ep);118 continue;119 }120 ParamCandidate ec = candidates.get(ep.getId());121 final Method adder = ec.getAdder();122 final Method remover = ec.getRemover();123 124 backend.adders.put(ep, new ReflectedAdder() {125 126 @Override127 public void reg(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {128 adder.invoke(object, listener);129 }130 });131 132 backend.removers.put(ep, new ReflectedRemover() {133 134 @Override135 public void regRemove(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {136 remover.invoke(object, listener);137 }138 });139 }140 141 for (final ValueParam vp : filterInstanceof(framsClass.getParamEntries(), ValueParam.class)) {142 if (!candidates.containsKey(vp.getId())) {143 throw new ConstructionException().msg("missing candidate for param").arg("param", vp);144 }145 ParamCandidate pc = candidates.get(vp.getId());146 if (pc.isReadOnly() && !vp.hasFlag(ParamFlags.READONLY)) {147 throw new ConstructionException().msg("readonly state conflict").arg("param", vp);148 }149 if (!typeMatch(pc.getRawType(), vp.getStorageType())) {150 throw new ConstructionException().msg("types mismatch for param").arg("param", vp).arg("candidate", pc.getType()).arg("storage", vp.getStorageType());151 }152 153 final boolean primitive = pc.isPrimitive();154 if (pc.getField() != null) {155 final Field f = pc.getField();156 backend.getters.put(vp, new ReflectedGetter() {157 @Override158 public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException {159 return type.cast(f.get(object));160 }161 });162 if (!pc.isFinal()) {163 backend.setters.put(vp, new ReflectedSetter() {164 @Override165 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException {166 if (value == null && primitive) {167 throw new FramsticksException().msg("setting null to primitive value");168 }169 f.set(object, value);170 }171 });172 }173 } else {174 final Method g = pc.getGetter();175 176 backend.getters.put(vp, new ReflectedGetter() {177 @Override178 public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {179 return type.cast(g.invoke(object));180 }181 });182 183 if (!pc.isFinal()) {184 final Method s = pc.getSetter();185 backend.setters.put(vp, new ReflectedSetter() {186 @Override187 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {188 if (value == null && primitive) {189 throw new FramsticksException().msg("setting null to primitive value");190 }191 s.invoke(object, value);192 }193 });194 }195 }196 }197 } catch (ConstructionException e) {198 throw e.arg("java class", reflectedClass).arg("framsClass", framsClass);199 }200 201 Class<?> javaClass = reflectedClass;202 while (javaClass != null) {203 204 for (Method m : javaClass.getDeclaredMethods()) {205 AutoAppendAnnotation a = m.getAnnotation(AutoAppendAnnotation.class);206 if (a == null) {207 continue;208 }209 Class<?>[] args = m.getParameterTypes();210 if (args.length != 1) {211 throw new ConstructionException().msg("invalid number of arguments in AutoAppend marked method").arg("method", m).arg("arguments", args.length);212 }213 backend.autoAppendMethods.add(m);214 }215 216 javaClass = javaClass.getSuperclass();217 }218 219 Collections.sort(backend.autoAppendMethods, new Comparator<Method>() {220 221 @Override222 public int compare(Method m0, Method m1) {223 Class<?> arg0 = m0.getParameterTypes()[0];224 Class<?> arg1 = m1.getParameterTypes()[0];225 if (arg0.isAssignableFrom(arg1)) {226 return 1;227 }228 if (arg1.isAssignableFrom(arg0)) {229 return -1;230 }231 return 0;232 }233 });234 235 synchronizedCache.put(id, backend);236 return backend;237 }238 239 }240 241 public static boolean typeMatch(Class<?> a, Class<?> b) {242 if (b.isPrimitive()) {243 throw new FramsticksException().msg("failed to match type, right argument is primitive").arg("left", a).arg("right", b);244 }245 if (!a.isPrimitive()) {246 return a.equals(b);247 }248 249 if (a.equals(int.class)) {250 return b.equals(Integer.class);251 }252 if (a.equals(double.class)) {253 return b.equals(Double.class);254 }255 if (a.equals(boolean.class)) {256 return b.equals(Boolean.class);257 }258 throw new FramsticksException().msg("failed to match types").arg("left", a).arg("right", b);259 }260 261 262 263 31 264 32 public ReflectionAccess(Class<?> javaClass) throws ConstructionException { … … 268 36 269 37 public ReflectionAccess(Class<?> javaClass, FramsClass framsClass) throws ConstructionException { 270 this(javaClass, framsClass, Backend.getOrCreateFor(javaClass, framsClass));271 } 272 273 protected ReflectionAccess(Class<?> javaClass, FramsClass framsClass, Backend backend) throws ConstructionException {38 this(javaClass, framsClass, ReflectionAccessBackend.getOrCreateFor(javaClass, framsClass)); 39 } 40 41 protected ReflectionAccess(Class<?> javaClass, FramsClass framsClass, ReflectionAccessBackend backend) throws ConstructionException { 274 42 super(framsClass); 275 43 this.javaClass = javaClass; … … 278 46 279 47 @Override 280 public ReflectionAccess cloneAccess() throws ConstructionException{48 public ReflectionAccess cloneAccess() { 281 49 return new ReflectionAccess(javaClass, framsClass, backend); 282 50 } … … 290 58 } 291 59 292 return backend.getters.get(param ).get(object, type);60 return backend.getters.get(param.getId()).get(object, type); 293 61 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 294 62 throw new FramsticksException().msg("failed to get").cause(e); … … 310 78 throw new FramsticksException().msg("no object set"); 311 79 } 312 Backend.ReflectedSetter s = backend.setters.get(param);80 ReflectionAccessBackend.ReflectedSetter s = backend.setters.get(param.getId()); 313 81 if (s == null) { 314 82 throw new FramsticksException().msg("trying to set unsettable"); … … 334 102 } 335 103 336 backend.adders.get(param ).reg(object, listener);104 backend.adders.get(param.getId()).reg(object, listener); 337 105 return; 338 106 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { … … 352 120 } 353 121 354 backend.removers.get(param ).regRemove(object, listener);122 backend.removers.get(param.getId()).regRemove(object, listener); 355 123 return; 356 124 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { … … 364 132 @Override 365 133 public Object call(String id, Object[] arguments) { 366 return call(framsClass.getParamEntry(id, ProcedureParam.class), arguments); 367 } 368 369 @Override 370 public Object call(ProcedureParam param, Object[] arguments) { 371 try { 372 try { 373 if (object == null) { 374 throw new FramsticksException().msg("no object set"); 375 } 376 Backend.ReflectedCaller c = backend.callers.get(param); 134 try { 135 try { 136 if (object == null) { 137 throw new FramsticksException().msg("no object set"); 138 } 139 ReflectionAccessBackend.ReflectedCaller c = backend.callers.get(id); 377 140 if (c == null) { 378 141 throw new FramsticksException().msg("method is not bound"); … … 383 146 } 384 147 } catch (FramsticksException e) { 385 throw e.arg("param", param).arg("access", this); 386 } 387 } 388 389 void resetErrors() { 390 //TODO this replaces returnedObject.resetErrors(); 148 throw e.arg("param", framsClass.getParam(id)).arg("access", this); 149 } 150 } 151 152 @Override 153 public Object call(ProcedureParam param, Object[] arguments) { 154 return call(param.getId(), arguments); 391 155 } 392 156 … … 396 160 return; 397 161 } 398 399 resetErrors();400 162 401 163 try { … … 416 178 @Override 417 179 public ReflectionAccess select(Object object) { 418 this.object = Util.selectObjectForAccess(this, object, javaClass);180 this.object = ParamsUtil.selectObjectForAccess(this, object, javaClass); 419 181 return this; 420 182 } … … 425 187 } 426 188 427 // TODO: find a better place for it428 public static String objectToString(Object object) {429 StringBuilder b = new StringBuilder();430 for (Field f : object.getClass().getFields()) {431 b.append(f.getName());432 b.append(":");433 try {434 Object value = f.get(object);435 b.append((value != null) ? value.toString() : "<null>");436 } catch (IllegalAccessException e) {437 e.printStackTrace();438 }439 b.append("\n");440 }441 return b.toString();442 }443 444 445 189 @Override 446 190 public Object createAccessee() { … … 448 192 return javaClass.newInstance(); 449 193 } catch (InstantiationException | IllegalAccessException e) { 450 e.printStackTrace(); 451 } 452 log.fatal("failed to create reflected object of class {} for frams type {}", javaClass.getCanonicalName(), framsClass.getId()); 453 return null; 454 } 455 194 throw new FramsticksException().msg("failed to create reflected object").arg("java class", javaClass).arg("frams class", framsClass).cause(e); 195 } 196 } 456 197 457 198 @Override
Note: See TracChangeset
for help on using the changeset viewer.