Java自定义注释和动态加载 [英] Java custom annotation and dynamic loading

查看:99
本文介绍了Java自定义注释和动态加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图发展ORM数据库同步,并决定给Java反射一展身手。我有一个定义这样的花样注释库

I'm trying to develop ORM for database synchronisation and decided to give Java reflection a go. I have a library that defines Synchronised annotation like this

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

在Android项目我使用此批注标记模型类

In android project I use this annotation to mark a model class

@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()返回正确的名称) - 这解释了为什么非我的previous尝试的成功。当试图直接铸造 - 铸造抛出异常(可以理解)。基本上,我不知所措我在这里,所以任何想法是值得欢迎的。

After some investigation a "loader" method was finally written that allows discovering model classes in current apk. It should retrieve all classes that are marked as "Synchronised", but the issue here is that getAttribute(Synchronised.class) doesn't work. Manually iterating annotations and searching for the attribute (instanceof, etc.) doesn't work either. When debugging I noticed that annotation coming from reflection is actually a proxy (getClass() gives "class Proxy2", while annotation.AnnotationType() returns correct name) - this explains why non of my previous attempts succeeded. When trying to cast directly - a cast exception is thrown (understandably). Basically I'm at a loss here so any idea is welcomed.

型号装载方法(在库项目):

Model loading method (in library project):

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;     
    }

[解决方案]的类加载器需要被捆绑,像这样的:

[SOLUTION] The class loader needs to be chained like this:

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

如果你仍然不知道我在说什么,感谢阅读这个漫长的职位( -

If you still have no idea what I'm talking about, thanks for reading this lengthy post (-.

推荐答案

得到的只是标注,你感兴趣的是:

Get just annotation that you are interested in:

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

更新:

问题在于DexFile.getClass()显然返回的代理。 OP已经找到了雁和更新解决这个问题。

The problem is that DexFile.getClass() apparently returns a proxy. OP has found the anser and updated the question with a solution.

这篇关于Java自定义注释和动态加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆