【问题标题】:Java custom annotation and dynamic loadingJava 自定义注解和动态加载
【发布时间】:2011-02-24 14:20:30
【问题描述】:

我正在尝试开发用于数据库同步的 ORM,并决定尝试使用 Java 反射。我有一个像这样定义同步注释的库

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface Synchronised {
    String tableName();
    SynchronisationType synchronisationType();
}

在android项目中我使用这个注解来标记一个模型类

@Synchronised(tableName="UserAccounts", synchronisationType=SynchronisationType.DownloadOnly)
public class UserAccount {   
    @SynchronisedField(fieldName="CompanyFk")
    private int companyId;
    @SynchronisedField(fieldName="Id")
    private int userId;
    @SynchronisedField(fieldName="Username")
    private String username;
    @SynchronisedField(fieldName="Password")
    private String password;
    @SynchronisedField(fieldName="Salt")
    private String salt;
    @SynchronisedField(fieldName="IsLocked")
    private boolean isLocked;
    @SynchronisedField(fieldName="HasMobileAccess")
    private boolean hasMobileAccess;
}

经过一番调查,最终编写了一个“加载器”方法,该方法允许发现当前 apk 中的模型类。它应该检索所有标记为“已同步”的类,但这里的问题是 getAttribute(Synchronised.class) 不起作用。手动迭代注释和搜索属性(instanceof 等)也不起作用。调试时,我注意到来自反射的注释实际上是一个代理(getClass() 给出“类 Proxy2”,而 annotation.AnnotationType() 返回正确的名称) - 这解释了为什么我之前的尝试都没有成功。尝试直接投射时 - 抛出异常(可以理解)。基本上我在这里不知所措,所以欢迎任何想法。

模型加载方式(在库项目中):

public static List<Class> getModels(Context context, String packageName)
        throws IOException, URISyntaxException, ClassNotFoundException,
            NameNotFoundException {

        String apkName = context.getPackageManager().getApplicationInfo(packageName, 0).sourceDir;
        DexFile dexFile = new DexFile(apkName);
        //PathClassLoader classLoader = new PathClassLoader(apkName, ClassLoader.getSystemClassLoader());       
        PathClassLoader classLoader = new PathClassLoader(apkName, Thread.currentThread().getContextClassLoader());

        List<Class> classes = new ArrayList<Class>();
        Enumeration<String> entries = dexFile.entries();

        while (entries.hasMoreElements()) {

            String entry = entries.nextElement();
            // only check items that exist in source package and not in libraries, etc.
            if (entry.startsWith(packageName)) {
                Log.d(TAG, "Entry: " + entry);

                Class<?> entryClass = classLoader.loadClass(entry);//dexFile.loadClass(entry, classLoader);
                if (entryClass != null) {
                    Annotation[] annotations = entryClass.getAnnotations();
                    for (Annotation annotation : annotations) {
                        if (annotation instanceof Synchronised) {
                            classes.add(entryClass);
                        }
                    }
                }
            }               
        }

        return classes;     
    }

[解决方案] 类加载器需要像这样链接:

PathClassLoader classLoader2 = new PathClassLoader(apkName, Thread.currentThread().getContextClassLoader());
DexClassLoader classLoader = new DexClassLoader(apkName, new ContextWrapper(context).getCacheDir().getAbsolutePath(), null, classLoader2);

如果您仍然不知道我在说什么,感谢您阅读这篇冗长的帖子 (-.

【问题讨论】:

    标签: java android reflection


    【解决方案1】:

    只获取您感兴趣的注释:

    Annotation<Synchronised> annotation = entryClass.getAnnotation(Synchronised.class);
    

    更新:

    问题在于 DexFile.getClass() 显然返回了一个代理。 OP 找到了分析器并用解决方案更新了问题。

    【讨论】:

    • 您在哪里找到了通用版本的 getAnnotations?我只能看到 getAnotation(class) 和 getAnnotations()。
    • 哦,我的错:它不返回数组。但它怎么可能 - 一个类只能有一个 Synchronized 类型的注释:developer.android.com/reference/java/lang/…
    • 没错,但这是我遇到的问题。 getAnnotation(Synchronised.class) 只返回 null。如果我使用 getAnnotations() 并遍历它,我可以看到我的注释,但它看起来像一个动态代理,因此即使比较类也不起作用。 annotation.getClass().toString() 给了我“类 Proxy2”,annotation.annotationType().toString() 给了我一个正确的类名。所以我假设可以从动态代理中检索我真正的注释对象,但我不确定如何。
    • 你试过 entryClass.isAnnotationPresent(..) 吗?
    • 如果 DexClass 真的返回代理,请尝试以不同的方式加载类:stackoverflow.com/questions/3022454/…
    猜你喜欢
    • 1970-01-01
    • 2014-01-13
    • 1970-01-01
    • 2011-06-12
    • 2018-10-25
    • 1970-01-01
    • 1970-01-01
    • 2016-06-02
    • 1970-01-01
    相关资源
    最近更新 更多