package org.rapidoid.render.retriever; /* * #%L * rapidoid-render * %% * Copyright (C) 2014 - 2017 Nikolche Mihajlovski and contributors * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import org.rapidoid.RapidoidThing; import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Since; import org.rapidoid.beany.BeanProp; import org.rapidoid.beany.Beany; import org.rapidoid.beany.Prop; import org.rapidoid.render.Getter; import org.rapidoid.u.U; import java.util.Collections; import java.util.List; import java.util.Map; @Authors("Nikolche Mihajlovski") @Since("5.2.0") public class GenericValueRetriever extends RapidoidThing implements ValueRetriever { private final String property; private volatile CachedPropRetriever cachedPropRetriever; public GenericValueRetriever(String property) { this.property = property; } @Override public Object retrieve(List<Object> model) { if (U.isEmpty(model)) return null; return getProp(model); } private Object getProp(List<Object> model) { Object target = U.last(model); Class<?> cls = target.getClass(); CachedPropRetriever cachedProp = cachedPropRetriever; if (cachedProp != null && cachedProp.canRetrieve(cls)) { return cachedProp.retrieve(target); } if (!(target instanceof Map)) { Prop prop = Beany.property(target, property, false); if (prop != null && prop instanceof BeanProp) { cachedPropRetriever = new CachedPropRetriever(cls, prop); return prop.getFast(target); } } return propOf(property, model); } public static Object self(List<Object> model) { return model.get(model.size() - 1); } public static Object propOf(String name, List<Object> scope) { int p = name.indexOf("."); if (p == 0) { U.must(name.length() == 1, "Invalid expression!"); return self(scope); } if (p > 0) { Object first = propOf(name.substring(0, p), scope); return propOf(name.substring(p + 1), Collections.singletonList(first)); } for (int i = scope.size() - 1; i >= 0; i--) { Object x = scope.get(i); if (x != null) { Object value = singleModelProp(name, x); if (value != null) return value; } } return null; } public static Object singleModelProp(String name, Object model) { if (model instanceof Map<?, ?>) { Map<?, ?> map = (Map<?, ?>) model; return map.get(name); } if (model instanceof Getter) { Getter getter = (Getter) model; return getter.get(name); } // process as bean Prop prop = Beany.property(model, name, false); if (prop != null) { return prop.get(model); } return null; // not found } }