All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.mustachejava.reflect.ReflectionObjectHandler Maven / Gradle / Ivy

There is a newer version: 0.9.14
Show newest version
package com.github.mustachejava.reflect;

import com.github.mustachejava.Binding;
import com.github.mustachejava.Code;
import com.github.mustachejava.ObjectHandler;
import com.github.mustachejava.TemplateContext;
import com.github.mustachejava.reflect.guards.*;
import com.github.mustachejava.util.GuardException;
import com.github.mustachejava.util.Wrapper;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * Lookup objects using reflection and execute them the same way.
 * 

* User: sam * Date: 7/24/11 * Time: 3:02 PM */ public class ReflectionObjectHandler extends BaseObjectHandler { protected static final Method MAP_METHOD; public static Object unwrap(ObjectHandler oh, int scopeIndex, Wrapper[] wrappers, Object[] scopes) throws GuardException { Object scope = oh.coerce(scopes[scopeIndex]); // The value may be buried by . notation if (wrappers != null) { for (Wrapper wrapper : wrappers) { scope = oh.coerce(wrapper.call(new Object[]{scope})); } } return scope; } static { try { MAP_METHOD = Map.class.getMethod("get", Object.class); } catch (NoSuchMethodException e) { throw new AssertionError(e); } } @SuppressWarnings("unchecked") @Override public Wrapper find(String name, final Object[] scopes) { Wrapper wrapper = null; final int length = scopes.length; List guards = new ArrayList(scopes.length); // Simple guard to break if the number of scopes at this call site have changed guards.add(createDepthGuard(length)); NEXT: for (int i = length - 1; i >= 0; i--) { Object scope = scopes[i]; if (scope == null) continue; // Make sure that the current scope is the same class guards.add(createClassGuard(i, scope)); List wrappers = null; int dotIndex; String subname = name; // If there is dot notation, start evaluating it while ((dotIndex = subname.indexOf('.')) != -1) { final String lookup = subname.substring(0, dotIndex); subname = subname.substring(dotIndex + 1); // This is used for lookups but otherwise always succeeds guards.add(createDotGuard(i, scope, lookup)); List wrapperGuard = new ArrayList(1); wrapper = findWrapper(0, null, wrapperGuard, scope, lookup); if (wrappers == null) wrappers = new ArrayList(); if (wrapper != null) { // We need to dig into a scope when dot notation shows up wrappers.add(wrapper); try { // Pull out the next level scope = coerce(wrapper.call(new Object[]{scope})); } catch (GuardException e) { throw new AssertionError(e); } } else { // Failed to find a wrapper for the next dot wrapperGuard.add(createClassGuard(0, scope)); guards.add(createWrappedGuard(i, wrappers, wrapperGuard)); continue NEXT; } if (scope == null) { // Found a wrapper, but the result of was null wrapperGuard.add(createNullGuard()); guards.add(createWrappedGuard(i, wrappers, wrapperGuard)); // Break here to allow the wrapper to be returned with the partial evaluation of the dot notation break; } } if (wrappers != null) { guards.add(createWrappedGuard(i, wrappers, Arrays.asList((Guard)createClassGuard(0, scope)))); } Wrapper[] foundWrappers = wrappers == null ? null : wrappers.toArray(new Wrapper[wrappers.size()]); wrapper = findWrapper(i, foundWrappers, guards, scope, subname); if (wrapper != null) { break; } } return wrapper == null ? createMissingWrapper(guards) : wrapper; } protected Wrapper findWrapper(final int scopeIndex, Wrapper[] wrappers, List guards, Object scope, final String name) { scope = coerce(scope); if (scope == null) return null; // If the scope is a map, then we use the get() method // to see if it contains a value named name. if (scope instanceof Map) { Map map = (Map) scope; if (map.containsKey(name)) { guards.add(createMapGuard(scopeIndex, wrappers, name, true)); return createWrapper(scopeIndex, wrappers, guards, MAP_METHOD, new Object[]{name}); } else { guards.add(createMapGuard(scopeIndex, wrappers, name, false)); if (!areMethodsAccessible(map)) { return null; } } } AccessibleObject member = findMember(scope.getClass(), name); return member == null ? null : createWrapper(scopeIndex, wrappers, guards, member, null); } // Factories protected MissingWrapper createMissingWrapper(List guards) { return new MissingWrapper(guards.toArray(new Guard[guards.size()])); } protected DotGuard createDotGuard(int i, Object scope, String lookup) { return new DotGuard(lookup, i, scope); } protected WrappedGuard createWrappedGuard(int i, List wrappers, List wrapperGuard) { return new WrappedGuard(this, i, wrappers, wrapperGuard); } protected NullGuard createNullGuard() { return new NullGuard(); } protected DepthGuard createDepthGuard(int length) { return new DepthGuard(length); } protected ClassGuard createClassGuard(int i, Object scope) { return new ClassGuard(i, scope); } protected MapGuard createMapGuard(int scopeIndex, Wrapper[] wrappers, String name, boolean contains) { return new MapGuard(this, scopeIndex, name, contains, wrappers); } @SuppressWarnings("unchecked") protected Wrapper createWrapper(int scopeIndex, Wrapper[] wrappers, List guard, AccessibleObject member, Object[] arguments) { return new ReflectionWrapper(scopeIndex, wrappers, guard.toArray(new Guard[guard.size()]), member, arguments, this); } @Override public Binding createBinding(String name, TemplateContext tc, Code code) { return new GuardedBinding(this, name, tc, code); } protected boolean areMethodsAccessible(Map map) { return false; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy