@Test public void setResolver() throws IOException { ValueResolver resolver = new ValueResolver() { @Override public Object resolve(final Object context) { return 1; } @Override public Object resolve(final Object context, final String name) { return 1; } @Override public Set<Entry<String, Object>> propertySet(final Object context) { return null; } }; Map<String, Object> hash = new HashMap<>(); hash.put("foo", "bar"); Context ctx = Context.newBuilder(hash).resolver(resolver).build(); assertEquals(1, ctx.get("foo")); assertEquals(1, ctx.get("bar")); }
public EngineHelper(Node node) { HashMap contextVariables = new HashMap(); contextVariables.put("node", node); this.node = node; this.context = Context.newBuilder(contextVariables) .resolver( MethodValueResolver.INSTANCE, MapValueResolver.INSTANCE, JavaBeanValueResolver.INSTANCE, FieldValueResolver.INSTANCE) .build(); }
@Override public CharSequence apply(final Object context, final Options options) throws IOException { if (context == null) { return null; } if (options.params.length <= 0) { return context.toString(); } Context ctx = Context.newBuilder(options.context, context).build(); Object lookup = ctx.get(options.param(0).toString()); if (lookup == null) { return null; } return lookup.toString(); }
/** * Lookup the given key inside the context stack. * * <ul> * <li>Objects and hashes should be pushed onto the context stack. * <li>All elements on the context stack should be accessible. * <li>Multiple sections per template should be permitted. * <li>Failed context lookups should be considered falsey. * <li>Dotted names should be valid for Section tags. * <li>Dotted names that cannot be resolved should be considered falsey. * <li>Dotted Names - Context Precedence: Dotted names should be resolved against former * resolutions. * </ul> * * @param key The object key. * @return The value associated to the given key or <code>null</code> if no value is found. */ public Object get(final String key) { // '.' or 'this' if (MUSTACHE_THIS.equals(key) || THIS.equals(key)) { return model; } // '..' if (key.equals(PARENT)) { return parent == null ? null : parent.model; } // '../' if (key.startsWith(PARENT_ATTR)) { return parent == null ? null : parent.get(key.substring(PARENT_ATTR.length())); } String[] path = toPath(key); Object value = get(path); if (value == null) { // No luck, check the extended context. value = get(extendedContext, key); // No luck, check the data context. if (value == null && data != null) { String dataKey = key.charAt(0) == '@' ? key.substring(1) : key; // simple data keys will be resolved immediately, complex keys need to go down and using a // new context. value = data.get(dataKey); if (value == null && path.length > 1) { // for complex keys, a new data context need to be created per invocation, // bc data might changes per execution. Context dataContext = Context.newBuilder(data).resolver(MapValueResolver.INSTANCE).build(); // don't extend the lookup further. dataContext.data = null; value = dataContext.get(dataKey); // destroy it! dataContext.destroy(); } } // No luck, but before checking at the parent scope we need to check for // the 'this' qualifier. If present, no look up will be done. if (value == null && !path[0].equals(THIS)) { value = get(parent, key); } } return value == NULL ? null : value; }