How do I use an ajc build parameter inside an aspect?

前端 未结 1 1346
梦毁少年i
梦毁少年i 2021-01-24 08:13

I need to know the name of my .jar inside the aspect so I can create a string field with it via @DeclareParents.

I know I can pass things to the ajc compiler, but is it

相关标签:
1条回答
  • 2021-01-24 08:37

    I do not know any way to do what you want. Even if it was possible, the string values would still be the same if you unpacked the JAR and loaded the modified classes from the file system or repackaged/renamed the JAR. The solution would be static, not dynamic.

    Anyway, how about putting information like that into a configuration file packaged into the JAR or maybe even right into the manifest file? Maven has capabilities to add information to the manifest and Java can read them during runtime. I have not thought it through, not to speak of trying to implement something like that, but maybe this is a way you can go.

    Feel free to ask follow-up questions.


    Update: You can avoid the manifest approach and try to directly determine the JAR file for each loaded class, see also this answer.

    Utility class:

    package de.scrum_master.util;
    
    import java.net.URL;
    
    public class ClassFileHelper {
        public static URL getClassURL(Class<?> clazz) {
            return clazz.getResource('/' + clazz.getName().replace('.', '/') + ".class");
        }
    
        public static String getJARFromURL(URL url) {
            if (!url.getProtocol().equals("jar"))
                return null;
            String fileName = url.getFile();
            fileName = fileName.substring(0, fileName.lastIndexOf('!'));
            fileName = fileName.substring(fileName.lastIndexOf('/') + 1);
            return fileName;
        }
    }
    

    Usage:

    I tried this in a Java + AspectJ project in which the aspects are wrapped in a JAR file and the Java files are stored in a file system directory. I just added the following advice to an aspect within the JAR:

    before() : execution(public static void main(..)) {
        try {
            Class<?>[] classes = { String.class, this.getClass(), Class.forName("com.BadReader") };
            for (Class<?> clazz : classes) {
                System.out.println(clazz);
                URL classURL = ClassFileHelper.getClassURL(clazz);
                System.out.println(classURL);
                System.out.println(ClassFileHelper.getJARFromURL(classURL));
                System.out.println();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    

    As you can see, the array contains

    • a JRE bootstrap class (String),
    • the aspect class itself (this.getClass()),
    • a class from the Java project outside the JAR (Class.forName("com.BadReader")).

    Console output:

    class java.lang.String
    jar:file:/C:/Programme/Java/jre7/lib/rt.jar!/java/lang/String.class
    rt.jar
    
    class com.SafeReaderAspect
    jar:file:/C:/Users/Alexander/Documents/java-src/SO_AJ_ITD2StepCompilation_AspectJ/aspectLib.jar!/com/SafeReaderAspect.class
    aspectLib.jar
    
    class com.BadReader
    file:/C:/Users/Alexander/Documents/java-src/SO_AJ_ITD2StepCompilation_Java/bin/com/BadReader.class
    null
    

    Is this what you want?

    0 讨论(0)
提交回复
热议问题