package se.dolkow.tangiblexml; import android.support.annotation.NonNull; import android.util.Pair; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import static java.lang.reflect.Modifier.FINAL; import static java.lang.reflect.Modifier.PUBLIC; import static java.lang.reflect.Modifier.STATIC; /** * If you want this to be useful, you'd better keep a hard reference yourself. The singleton is * weakly linked, so if no one holds a reference, it'll be garbage collected. */ class TangibleFieldCache { private static @NonNull WeakReference<TangibleFieldCache> instance = new WeakReference<>(null); private final @NonNull HashMap<Class,Pair<Field,TangibleField>[]> map; public synchronized static TangibleFieldCache getInstance() { TangibleFieldCache cache = instance.get(); if (cache == null) { cache = new TangibleFieldCache(); instance = new WeakReference<>(cache); } return cache; } private TangibleFieldCache() { map = new HashMap<>(); } public synchronized @NonNull Pair<Field,TangibleField>[] get(@NonNull Class clazz) throws InvalidFieldException { Pair<Field,TangibleField>[] fields = map.get(clazz); if (fields != null) { return fields; } ArrayList<Pair<Field,TangibleField>> flist = new ArrayList<>(); find(clazz, flist); //noinspection unchecked fields = flist.toArray(new Pair[flist.size()]); map.put(clazz, fields); return fields; } private synchronized void find(final @NonNull Class clazz, final @NonNull ArrayList<Pair<Field,TangibleField>> out) throws InvalidFieldException { Class cur = clazz; while (cur != null) { for (Field f : cur.getDeclaredFields()) { TangibleField tang = f.getAnnotation(TangibleField.class); if (tang != null) { if (f.getType().isPrimitive()) { // primitives make the already-set (i.e. null) check hard... throw new InvalidFieldException("Field " + f + " may not be primitive"); } int mod = f.getModifiers(); if ((mod & PUBLIC) != PUBLIC) { throw new InvalidFieldException("Field " + f + " must be public"); } else if ((mod & (STATIC|FINAL)) != 0) { String msg = "Field " + f + " may not be static or final"; throw new InvalidFieldException(msg); } out.add(new Pair<>(f, tang)); } } cur = cur.getSuperclass(); } } }