001package io.ebean.enhance.querybean; 002 003import java.util.HashSet; 004import java.util.Set; 005 006/** 007 * Detects if a class is a query bean. 008 * <p> 009 * Used by enhancement to detect when GETFIELD access on query beans should be replaced by 010 * appropriate method calls. 011 * </p> 012 */ 013public class DetectQueryBean { 014 015 private final Set<String> entityPackages = new HashSet<>(); 016 017 public DetectQueryBean() { 018 } 019 020 public void addAll(Set<String> rawEntityPackages) { 021 for (String rawEntityPackage : rawEntityPackages) { 022 entityPackages.add(convert(rawEntityPackage)); 023 } 024 } 025 026 /** 027 * Convert package to slash notation taking into account trailing wildcard. 028 */ 029 private static String convert(String pkg) { 030 031 pkg = pkg.trim(); 032 if (pkg.endsWith("*")) { 033 pkg = pkg.substring(0, pkg.length() - 1); 034 } 035 if (pkg.endsWith(".query")) { 036 // always work with entity bean packages so trim 037 pkg = pkg.substring(0, pkg.length() - 6); 038 } 039 pkg = pkg.replace('.', '/'); 040 return pkg.endsWith("/") ? pkg : pkg + "/"; 041 } 042 043 044 @Override 045 public String toString() { 046 return entityPackages.toString(); 047 } 048 049 /** 050 * Return true if there are no known packages. 051 */ 052 public boolean isEmpty() { 053 return entityPackages.isEmpty(); 054 } 055 056 /** 057 * Return true if this class is a query bean using naming conventions for query beans. 058 */ 059 public boolean isQueryBean(String owner) { 060 061 int subPackagePos = owner.lastIndexOf("/query/"); 062 if (subPackagePos > -1) { 063 String suffix = owner.substring(subPackagePos); 064 if (isQueryBeanSuffix(suffix)) { 065 String domainPackage = owner.substring(0, subPackagePos + 1); 066 return isQueryBeanPackage(domainPackage); 067 } 068 } 069 return false; 070 } 071 072 /** 073 * Check that the class is in an expected package (sub package of a package containing entity beans). 074 */ 075 private boolean isQueryBeanPackage(String domainPackage) { 076 for (String aPackage : entityPackages) { 077 if (domainPackage.startsWith(aPackage)) { 078 return true; 079 } 080 } 081 return false; 082 } 083 084 /** 085 * Check that the class follows query bean naming convention. 086 */ 087 private boolean isQueryBeanSuffix(String suffix) { 088 return (suffix.startsWith("/query/Q") || suffix.startsWith("/query/assoc/Q")); 089 } 090}