Search code examples
aopaspectj

How do I override Class<?>.getName() for certain classes?


My goal is to be able to override what I get back from CustomClass.class.getName() and CustomClass.getClass().getName()

It should return a custom value, which I think is best to define in an attribute like

@NameOverride("Custom.fully.qualified.class.name")
public class CustomClass {}

Is there any way to do that?


Solution

  • Fred's answer is okay, but his aspect could be somewhat more elegant with less code and especially fewer reflection calls. Sorry, I prefer AspectJ native code style, but @AspectJ annotation style would not be much longer:

    String around(Class clazz) : call(public String Class.getName()) && target(clazz) {
        NameOverride nameOverride = (NameOverride) clazz.getAnnotation(NameOverride.class);
        return nameOverride == null ? proceed(clazz) : nameOverride.value();
    }
    

    Here is the full source code. I added a class without annotation to show the different behaviour and also a restriction to class definitions - @Target(ElementType.TYPE) - to the annotation class. I am also showing package names and imports:

    package test;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface NameOverride {
        String value();
    }
    
    package test;
    
    public class NormalClass {}
    
    package test;
    
    @NameOverride("Custom.fully.qualified.class.name")
    public class CustomClass {}
    
    package test;
    
    public class Main {
        public static void main(String[] args) {
            System.out.println(NormalClass.class.getName());
            System.out.println(CustomClass.class.getName());
            System.out.println(new NormalClass().getClass().getName());
            System.out.println(new CustomClass().getClass().getName());
        }
    }
    
    package aspectj;
    
    import test.NameOverride;
    
    public aspect GetNameOverrider {
        @SuppressWarnings({ "unchecked", "rawtypes" })
        String around(Class clazz) : call(public String Class.getName()) && target(clazz) {
            NameOverride nameOverride = (NameOverride) clazz.getAnnotation(NameOverride.class);
            return nameOverride == null ? proceed(clazz) : nameOverride.value();
        }
    }
    

    The output:

    test.NormalClass
    Custom.fully.qualified.class.name
    test.NormalClass
    Custom.fully.qualified.class.name