001package io.ebean.enhance.common;
002
003import io.ebean.enhance.asm.ClassReader;
004
005import java.util.HashMap;
006import java.util.Map;
007
008/**
009 * Reads class information as an alternative to using a ClassLoader.
010 * <p>
011 * Used because if annotation classes are not in the classpath they are silently
012 * dropped from the class information. We are especially interested to know if
013 * super classes are entities during enhancement.
014 * </p>
015 */
016public class ClassMetaReader {
017
018        private final Map<String, ClassMeta> cache = new HashMap<>();
019
020        private final EnhanceContext enhanceContext;
021
022        public ClassMetaReader(EnhanceContext enhanceContext) {
023                this.enhanceContext = enhanceContext;
024        }
025
026        public ClassMeta get(boolean readMethodAnnotations, String name, ClassLoader classLoader) throws ClassNotFoundException {
027                return getWithCache(readMethodAnnotations, name, classLoader);
028        }
029
030        private ClassMeta getWithCache(boolean readMethodAnnotations, String name, ClassLoader classLoader) throws ClassNotFoundException {
031                
032                synchronized (cache) {
033                        ClassMeta meta = cache.get(name);
034                        if (meta == null) {
035                                meta = readFromResource(readMethodAnnotations, name, classLoader);
036                                if (meta != null) {
037                                        if (meta.isCheckSuperClassForEntity()) {
038                                                ClassMeta superMeta = getWithCache(readMethodAnnotations, meta.getSuperClassName(), classLoader);
039                                                if (superMeta != null && superMeta.isEntity()) {
040                                                        meta.setSuperMeta(superMeta);
041                                                }
042                                        }
043                                        cache.put(name, meta);
044                                }
045                        }
046                        return meta;
047                }
048        }
049
050        private ClassMeta readFromResource(boolean readMethodAnnotations, String className, ClassLoader classLoader)
051                        throws ClassNotFoundException {
052
053                byte[] classBytes = enhanceContext.getClassBytes(className, classLoader);
054                if (classBytes == null){
055                  if (enhanceContext.isLog(2)) {
056              enhanceContext.log(null, "Could not read meta data for class ["+className+"].");              
057                  }
058                        return null;
059                } else {
060                        if (enhanceContext.isLog(5)) {
061                                enhanceContext.log(className, "read ClassMeta");
062                        }
063                }
064                ClassReader cr = new ClassReader(classBytes);
065                ClassMetaReaderVisitor ca = new ClassMetaReaderVisitor(readMethodAnnotations, enhanceContext);
066                cr.accept(ca, ClassReader.SKIP_FRAMES + ClassReader.SKIP_DEBUG);
067
068                return ca.getClassMeta();
069        }
070
071}