package act.data; /*- * #%L * ACT Framework * %% * Copyright (C) 2014 - 2017 ActFramework * %% * 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 act.app.App; import act.app.AppServiceBase; import act.util.ActContext; import act.util.PropertySpec; import org.joda.time.*; import org.osgl.util.C; import org.rythmengine.utils.S; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; import java.util.*; /** * Keep the property information of Data class */ public class DataPropertyRepository extends AppServiceBase<DataPropertyRepository> { /** * all classes that can NOT be decomposed in terms of get properties */ private Set<Class> terminators; /** * name of terminator classes. */ private Set<String> extendedTerminators; /** * Map a list of property path to class name */ private Map<String, List<String>> repo = C.newMap(); private OutputFieldsCache outputFieldsCache = new OutputFieldsCache(); public DataPropertyRepository(App app) { super(app, true); _init(); } @Override protected void releaseResources() { extendedTerminators.clear(); terminators.clear(); repo.clear(); } /** * Returns the complete property list of a class * @param c the class * @return the property list of the class */ public synchronized List<String> propertyListOf(Class<?> c) { String cn = c.getName(); List<String> ls = repo.get(cn); if (ls != null) { return ls; } ls = buildPropertyList(c); repo.put(cn, ls); return ls; } public List<String> outputFields(PropertySpec.MetaInfo spec, Class<?> componentClass, ActContext context) { return outputFieldsCache.getOutputFields(spec, componentClass, context); } private List<String> buildPropertyList(Class c) { Method[] ma = c.getMethods(); String context = ""; List<String> retLst = C.newList(); for (Method m: ma) { buildPropertyPath(context, m, retLst); } return retLst; } private void buildPropertyPath(String context, Method m, List<String> repo) { if (m.getParameterTypes().length > 0) { return; } String name = m.getName(); if ("getClass".equals(name)) { return; } String propName = ""; if (name.startsWith("get")) { propName = getPropName(name); } else if (name.startsWith("is")) { propName = isPropName(name); } if (S.isEmpty(propName)) { return; } Class c = m.getReturnType(); if (Class.class.equals(c)) { return; } if (Enum.class.isAssignableFrom(c)) { repo.add(context + propName); return; } if (Iterable.class.isAssignableFrom(c)) { Type t = m.getGenericReturnType(); if (t instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) t; Type[] ta = pt.getActualTypeArguments(); for (Type t0: ta) { Class<?> c0 = (Class) t0; List<String> retTypeProperties = propertyListOf(c0); context = context + propName + "."; for (String s: retTypeProperties) { repo.add(context + s); } } } return; } if (terminators.contains(c) || extendedTerminators.contains(c.getName())) { repo.add(context + propName); return; } List<String> retTypeProperties = propertyListOf(c); context = context + propName + "."; for (String s : retTypeProperties) { repo.add(context + s); } } private static String getPropName(String name) { return S.lowerFirst(name.substring(3)); } private static String isPropName(String name) { return S.lowerFirst(name.substring(2)); } private void _init() { Set<Class> s = C.newSet(); s.add(boolean.class); s.add(byte.class); s.add(char.class); s.add(short.class); s.add(int.class); s.add(float.class); s.add(long.class); s.add(double.class); s.add(Boolean.class); s.add(Byte.class); s.add(Character.class); s.add(Short.class); s.add(Integer.class); s.add(Float.class); s.add(Long.class); s.add(Double.class); s.add(BigDecimal.class); s.add(BigInteger.class); s.add(String.class); s.add(Date.class); s.add(java.sql.Date.class); s.add(Calendar.class); s.add(DateTime.class); s.add(Instant.class); s.add(LocalDate.class); s.add(LocalDateTime.class); s.add(LocalTime.class); terminators = s; Set<String> s0 = C.newSet(); for (Class c: s) { s0.add(c.getName()); } s0.add("java.time.Instant"); s0.add("java.time.LocalTime"); s0.add("java.time.LocalDate"); s0.add("java.time.LocalDateTime"); s0.add("org.bson.types.ObjectId"); extendedTerminators = s0; } }