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