Neden eksik bir ek açıklama çalışma zamanında ClassNotFoundException'a neden olmuyor?


91

Aşağıdaki kodu göz önünde bulundurun:

A. java:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@interface A{}

C. java:

import java.util.*;

@A public class C {
        public static void main(String[] args){
                System.out.println(Arrays.toString(C.class.getAnnotations()));
        }
}

Derleme ve çalıştırma, beklendiği gibi çalışır:

$ javac *.java
$ java -cp . C
[@A()]

Ama sonra şunu düşünün:

$ rm A.class
$ java -cp . C
[]

Bir atmak için beklerdim ClassNotFoundExceptionberi @Akayıp. Ancak bunun yerine ek açıklamayı sessizce bırakır.

Bu davranış JLS'de bir yerde belgelenmiş mi, yoksa Sun'ın JVM'sinin bir tuhaflığı mı? Bunun mantığı nedir?

javax.annotation.Nonnull( @Retention(CLASS)Zaten olması gerektiği gibi görünüyor) gibi şeyler için uygun görünüyor , ancak diğer birçok ek açıklama için çalışma zamanında çeşitli kötü şeylerin olmasına neden olabilir gibi görünüyor.

Yanıtlar:


90

JSR-175 (ek açıklamalar) için daha önceki genel taslaklarda, ek açıklamaların kullanımı ve bildirimi arasında daha gevşek bir bağlantı sağlamak için derleyicinin ve çalışma zamanının bilinmeyen ek açıklamaları yoksayması gerekip gerekmediği tartışılmıştı. Spesifik bir örnek, dağıtım yapılandırmasını kontrol etmek için bir EJB'de uygulama sunucusuna özel açıklamaların kullanılmasıydı. Aynı çekirdeğin farklı bir uygulama sunucusunda dağıtılması gerekiyorsa, çalışma zamanının bir NoClassDefFoundError hatası yükseltmek yerine bilinmeyen ek açıklamaları yok sayması daha uygun olurdu.

İfadeler biraz belirsiz olsa bile, gördüğünüz davranışın JLS 13.5.7'de belirtildiğini varsayıyorum: "... ek açıklamaların kaldırılmasının, Java programlama dilinde programların ikili gösterimlerinin doğru bağlantısı üzerinde hiçbir etkisi yoktur . " Bunu, ek açıklamalar kaldırılmış gibi yorumluyorum (çalışma zamanında mevcut değil), program yine de bağlanmalı ve çalışmalıdır ve bu, yansıma yoluyla erişildiğinde bilinmeyen ek açıklamaların basitçe yok sayılacağı anlamına gelir.

Sun'ın JDK 5'inin ilk sürümü bunu doğru bir şekilde uygulamadı, ancak 1.5.0_06'da düzeltildi. İlgili hata 6322301'i hata veritabanında bulabilirsiniz, ancak "JSR-175 spesifikasyonuna göre, bilinmeyen ek açıklamaların getAnnotations tarafından göz ardı edilmesi gerektiği" iddiası dışında herhangi bir spesifikasyona işaret etmez.


35

JLS'den alıntı yapmak:

9.6.1.2 Saklama Açıklamaları yalnızca kaynak kodda veya bir sınıf veya arayüzün ikili biçiminde mevcut olabilir. İkili dosyada bulunan bir açıklama, Java platformunun yansıtıcı kitaplıkları aracılığıyla çalışma zamanında mevcut olabilir veya olmayabilir.

Ek açıklama türü ek açıklaması Saklama, yukarıdaki olasılıklar arasından seçim yapmak için kullanılır. Bir açıklama a, bir T tipine karşılık geliyorsa ve T, açıklamaya karşılık gelen bir (meta) ek açıklamaya sahipse.

  • M, değeri annotation.RetentionPolicy.SOURCE olan bir öğeye sahipse, bir Java derleyicisi, a'nın göründüğü sınıfın veya arabirimin ikili gösteriminde a'nın bulunmadığından emin olmalıdır.
  • M, değeri annotation.RetentionPolicy.CLASS veya annotation.RetentionPolicy.RUNTIME olan bir öğeye sahipse, bir Java derleyicisi, m bir yerel değişken bildirimine açıklama eklemediği sürece a'nın göründüğü sınıfın veya arabirimin ikili gösteriminde a'nın temsil edilmesini sağlamalıdır. . Yerel değişken bildirimindeki bir açıklama, ikili gösterimde asla tutulmaz.

T'nin açıklamaya karşılık gelen bir (meta) ek açıklaması yoksa, o zaman bir Java derleyicisinin T'yi, değeri annotation.RetentionPolicy.CLASS olan bir öğeyle böyle bir meta ek açıklaması varmış gibi ele alması gerekir.

Dolayısıyla RetentionPolicy.RUNTIME, ek açıklamanın ikili dosyada derlenmesini sağlar, ancak ikili dosyada bulunan bir ek açıklamanın çalışma zamanında mevcut olması gerekmez.


9

Aslında @A okuyan ve onunla bir şeyler yapan kodunuz varsa, kodun A sınıfına bağımlılığı vardır ve ClassNotFoundException oluşturur.

eğer değilse, yani hiçbir kod özellikle @A ile ilgilenmez, o zaman @A'nın gerçekten önemli olmadığı tartışılabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.