I have a method with a generic varargs parameter in my API. I want my API to be Java 6 source and binary compatible, but it would be nice if Java 7 API consumers wouldn't suffer from unnecessary "varargs"
warnings.
A trick that I can think of is to add my own java.lang.SafeVarargs
annotation to my API and ship it with my deliverable. As an effect:
Apart from license concerns, is this guaranteed to work? It seems to work with javac. Or are there configurations where re-defining an annotation from the JDK has undesireable side-effects at the call-site? Or is there another way to solve this Java 6/7 interoperability issue?
A related question:
Question: is this guaranteed to work?
Answer: it depends. I would like to point out one potential issue.
The "real" @SafeVarargs annotation is declared with RetentionPolicy.RUNTIME (see here). The reason for this (in contrast with @Override, which has RetentionPolicy.SOURCE) is probably to allow the compiler to check for it at the calling site. However,
THEN any code which uses Reflection to get the method annotations at runtime (e.g. Spring framework) will fail miserably with SecurityException because the package name of the annotation starts with "java." (see the relevant code from the ClassLoader.preDefineClass() method and the stactrace below, both from Sun JRE 1.6.0_31).
If the annotation is on the classpath at compile time but not at runtime ("provided" scope in maven) then there is no exception thrown (at least with Sun JRE).
The best solution would be to have some Maven artifact like java.lang.java7-annotations at disposal and use it with scope "provided". I found something here (artifact: com.google.backport.safevarargs) but it is not in the central repo.
if ((name != null) && name.startsWith("java.")) { throw new SecurityException("Prohibited package name: " + name.substring(0, name.lastIndexOf('.'))); }
Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang at java.lang.ClassLoader.preDefineClass(ClassLoader.java:479) at java.lang.ClassLoader.defineClassCond(ClassLoader.java:625) at java.lang.ClassLoader.defineClass(ClassLoader.java:615) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141) at java.net.URLClassLoader.defineClass(URLClassLoader.java:283) at java.net.URLClassLoader.access$000(URLClassLoader.java:58) at java.net.URLClassLoader$1.run(URLClassLoader.java:197) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With