Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are annotation string values not interned?

The following snippet prints 4 distinct hash codes, despite reusing a string constant and literal. Why are string values not interned on annotation elements?

public class Foo {
    @Retention(RetentionPolicy.RUNTIME)
    @interface Bar {
        String CONSTANT = "foo";

        String value() default CONSTANT;
    }

    public static void main(String[] args) throws Exception {
        System.out.println(System.identityHashCode(Bar.CONSTANT));
        System.out.println(System.identityHashCode(Foo.class.getMethod("test1").getAnnotation(Bar.class).value()));
        System.out.println(System.identityHashCode(Foo.class.getMethod("test2").getAnnotation(Bar.class).value()));
        System.out.println(System.identityHashCode(Foo.class.getMethod("test3").getAnnotation(Bar.class).value()));
    }

    @Bar
    public void test1() {}

    @Bar("foo")
    public void test2() {}

    @Bar(Bar.CONSTANT)
    public void test3() {}
}
like image 446
shmosel Avatar asked Jun 16 '16 07:06

shmosel


People also ask

Are all Java strings interned?

intern() in Java. All compile-time constant strings in Java are automatically interned using this method. String interning is supported by some modern object-oriented programming languages, including Java, Python, PHP (since 5.4), Lua,Julia and . NET languages.

Are Javascript strings interned?

Yes. In general any literal string, identifier, or other constant string in JS source is interned. However implementation details (exactly what is interned for instance) varies, as well as when the interning occurs.

Can we apply two annotations together?

It is also possible to use multiple annotations on the same declaration: @Author(name = "Jane Doe") @EBook class MyClass { ... } If the annotations have the same type, then this is called a repeating annotation: @Author(name = "Jane Doe") @Author(name = "John Smith") class MyClass { ... }

Why are annotations used in Java?

Annotations are used to provide supplemental information about a program. Annotations start with '@'. Annotations do not change the action of a compiled program. Annotations help to associate metadata (information) to the program elements i.e. instance variables, constructors, methods, classes, etc.


2 Answers

String literal are interned but annotations are subject to parse and they are stored in byte arrays. If you look at the class java.lang.reflect.Method you can see this:

private byte[]              annotations;
private byte[]              parameterAnnotations;
private byte[]              annotationDefault;  

Take also a look at the method public Object getDefaultValue() of the same class to see how the AnnotationParser is called. The flow continues till here AnnotationParser.parseConst and enter in

case 's':
  return constPool.getUTF8At(constIndex);

The method ConstantPool.getUTF8At is a delegate to a native method. You can see the code here native implementation getUFT8At. The parsed constant is never interned and is never retrieved from the StringTable (where string are interned).

I think it could be a choice of implementation. Interning has been created to make more fast comparison between String literal and so is used only for interning literal usable in method implementation.

like image 172
Aris2World Avatar answered Sep 30 '22 00:09

Aris2World


It's because you access to annotation at runtime and accordance with java spec - Example 3.10.5-1. String Literals, strings are newly created and therefore distinct.

All literal strings and compile-time string-valued constant expressions are automatically interned

In your case the value from test1 will be computed at runtime from native value() method (look at AnnotationDefault attribute).

String value() default CONSTANT;

Others cases also will be computed at runtime.

When you get a value from the annotation you have to explicitly to perform intern

String poolString = Foo.class.getMethod("test1").getAnnotation(Bar.class).value().intern();
System.out.println(poolString == Bar.CONSTANT); 
like image 42
Eugene Kirin Avatar answered Sep 30 '22 01:09

Eugene Kirin