I am trying to add JetBrains Annotations library to my code.
Now I come across, that if I generate JavaDoc of my code the appearance of them is duplicated. Once is without qualifier (the annotations are imported, so no one is needed) and the second one (sometimes) with qualifier.
There are also cases where the annotation is only once there but on two parameters one is without qualifier and the other with one.
A code snippet:
public Subnet(#NotNull String[] ip){/*...*/}
/*...*/
public Subnet(#NotNull int[] ip) {/*...*/}
Generated JavaDoc:
public Subnet(#NotNull #NotNull String[] ip){/*...*/}
/*...*/
public Subnet(#NotNull #org.jetbrains.annotations.NotNull int[] ip) {/*...*/}
I tried the -noqualifier option but it did not help.
I am using the JavaDoc plugin version 3.1.1 and Doclet version 11.0.7.
Is there a way to get rid of the duplicated annotations?
Related
I am working with AspectJ at the moment.
I seperated AspectJ code in a dependency.
Within that dependency everything works as intended.
But as soon as I import it in another project only some functionality does not work anymore.
When using the defaultImpl of #DeclareParents, the interface is shown within the compiled code but not the default Implementation.
Here is my code to show what I mean (every code snippet is its own File):
AspectJ code:
public interface IAspect
{
String hello();
}
public class IAspectDefaultImpl implements IAspect
{
#Override
public String hello()
{
return "hello";
}
}
#Aspect
public class AspectJ
{
#DeclareParents(value = "#SomeAnnotation*", defaultImpl = IAspectDefaultImpl.class)
private IAspect implementedInterface;
}
Target Class in a different project:
#SomeAnnotation
public class MyClass
{
private final int myValue;
public MyClass(final int wert)
{
this.myValue = wert;
}
public int getMyValue()
{
return myValue;
}
}
Maven throws me:
The type MyClass must implement the inherited abstract method IAspect.hello()
Which implies that it works partially.
When looking at the decompiled .class files the targeted Class does in fact implement IAspect.
The method defined in IAspectDefaultImpl is still missing tho.
My pom is set up like in this example.
I am not sure where I should start to look for errors.
Any help is apreciated.
Thanks for the MCVE. But hey, you don't use Git in order to commit 7z or ZIP archives, you ought to commit source code. I forked your project and fixed that, restructured and simplified your POMs and also fixed the main problem.
See my pull request and the commits in it for further details.
Concerning your problem, I can confirm that it occurs if you use #DeclareParents the way you do in an aspect library.
Actually, according to AspectJ maintainer Andy Clement there are certain problems with #DeclareParents when using it to provide parent interfaces + implementations in annotation style. The native AspectJ syntax via declare parents is not affected by that, but for annotation-style syntax Andy provided an alternative called #DeclareMixin, see the AspectJ manual. There he mentions that he is even considering to deprecate the defaultImpl argument of #DeclareParents in favour of #DeclareMixin.
So my bugfix (or workaround) for your problems is to actually replace
#DeclareParents(value = "#de.example.aspect.SomeAnnotation *", defaultImpl = IAspectDefaultImpl.class)
private IAspect implementedInterface;
by
#DeclareMixin("#de.example.aspect.SomeAnnotation *")
public static IAspect createIAspectImplementation() {
return new IAspectDefaultImpl();
}
This works with aspect libraries.
I will discuss with Andy about whether it makes sense to file a bug ticket for your problem or if he won't fix it anyway because there is a viable and recommended alternative.
I am running an annotation processor that I have wrote. It ran fine on JDK 8 and now I am experiencing a problem on JDK 12.
I have a TypeElement and I want to retrieve its binary name to pass to Class.forName.
I use javax.lang.model.util.Elements.getBinaryName(TypeElement) and it returns a garbage value <any?>$OuterClass.InnerClass instead of the expected example3.OuterClass$InnerClass.
I attempted to replace getBinaryName with TypeElement.getQualifiedName (even though it would not quite work for an inner class) but it gives me the same garbage result. I have tried searching for this issue but most search engines strip all the special characters and give me useless results.
The TypeElement was obtained by catching a MirroredTypeException like so:
try {
exampleAnnotation.value();
throw new IllegalStateException("Expected a MirroredTypeException.");
} catch (MirroredTypeException ex) {
return (TypeElement) types.asElement(ex.getTypeMirror());
}
And here is the definition of ExampleAnnotation:
package example1;
#Target(PACKAGE)
#Retention(RUNTIME)
#Documented
public #interface ExampleAnnotation {
Class<? extends Derived> value() default Derived.class;
interface Derived<A extends Annotation> extends Base<A> {
String foo();
}
}
And here is the instance of the annotation that the processor is accessing in package-info.java:
#ExampleAnnotation(OuterClass.InnerClass.class)
package example2;
import example1.ExampleAnnotation;
I have also tried the fully qualified name example3.OuterClass.InnerClass.class but that also results in garbage: <any?>$example3.OuterClass.InnerClass.
I doubt it matters but the annotation processors are still marked #SupportedSourceVersion(SourceVersion.RELEASE_8) and I am running this on Gradle 5.3.1.
I've verified the processorpath contains the jars for packages example1 and example3, including the annotation processors.
I've made no changes to account for the module system so I was thinking maybe that's somehow affecting the code.
Just tried creating a Maven project and am currently unable to reproduce the problem, so there may be an issue with my Gradle configuration, similar to what #Colin Alworth has suggested.
I had recently upgraded to a new version of Gradle and started using the "annotationProcessor" dependencies.
It appears that <any?>$ is prepended to binary/qualified class names (as it appears in the source) if the class isn't on the classpath (or if it isn't imported, or is spelled wrong). I only had the annotation's jar on the processorpath.
To alert consumers of my annotation processor of this mistake, I was able to detect it by comparing TypeElement.asType().getKind() == TypeKind.ERROR immediately after catching the MirroredTypeException.
Javadoc (via Maven) is giving me the following error in one my Java JAX-RS interface method signatures:
error: element value must be a constant expression
Here is my JAX-RS interface:
public interface FooResource {
#Consumes(APPLICATION_FORM_URLENCODED_UTF_8)
public void bar();
}
Javdoc gives the error for #Consumes. Here is the definition for APPLICATION_FORM_URLENCODED_UTF_8, which appears in MyAppConstants in the same project:
public static final String APPLICATION_FORM_URLENCODED_UTF_8 =
APPLICATION_FORM_URLENCODED + ";" + CHARSET_PARAMETER + "=UTF-8";
And here is the definition of APPLICATION_FORM_URLENCODED, which appears in javax.ws.rs.core.MediaType:
public final static String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded";
And here is the definition of CHARSET_PARAMETER, which also appears in javax.ws.rs.core.MediaType:
public static final String CHARSET_PARAMETER = "charset";
Now I ask you: what about APPLICATION_FORM_URLENCODED_UTF_8 is not constant at compile time?
The error message didn't say that I have to provide a literal. It said I had to provide a constant. So what about this is not a constant?
(I could almost swear that this worked at one time but suddenly stopped working.)
Update: Found cause, but still don't understand.
For some reason, merely including the swagger-maven-plugin in the POM will trigger this problem! My code doesn't change at all, but as soon as I add the following dependency, suddenly I get Javadoc warnings for my existing code!!!
<dependency>
<groupId>com.github.kongchen</groupId>
<artifactId>swagger-maven-plugin</artifactId>
<version>3.1.5</version>
</dependency>
How can a single dependency make Javadoc work differently on a code file? What is swagger-maven-plugin doing?
My best guess is that this happens because swagger-maven-plugin transitively (via io.swagger:swagger-core:1.5.13) an old version of the JAX-RS specification in javax.ws.rs:jsr311-api:1.1.1. Note that the JAX-RS 2 artifact ID is javax.ws.rs-api, Maven doesn't realize that they are different versions of the same JAR, and pulls them both in as dependencies. I can only guess that javax.ws.rs:jsr311-api in fact does not use constants for the variables in question. In any case, when I threw out swagger-maven-plugin and pulled in io.swagger:swagger-annotations (which was all I needed in this project for documentation), the problem went away.
See https://github.com/kongchen/swagger-maven-plugin/issues/543.
I am new to Junit4, I am wondering if there is some annotations to mark a class as a test class just like using
#Test to mark a method as a test method.
You can use #Category annotation at class level, like:
#Category({PerformanceTests.class, RegressionTests.class})
public class ClassB {
#Test
public void test_b_1() {
assertThat(1 == 1, is(true));
}
}
I quoted this example from https://www.mkyong.com/unittest/junit-categories-test/
Also if you run Spring tests, Mockito test with JUnit, then you have to use #RunWith annotation at class level.
For example in Spring boot test I use this:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
public class ControllerTest {
In Mockito (without spring test) test I used:
#RunWith(MockitoJUnitRunner.class)
public class ServiceTest {
Annotation #TestOnly, but it does come with a warning, as seen below.
import org.jetbrains.annotations.TestOnly;
WARNING
/**
* A member or type annotated with TestOnly claims that it should be used from testing code only.
* <p>
* Apart from documentation purposes this annotation is intended to be used by static analysis tools
* to validate against element contract violations.
* <p>
* This annotation means that the annotated element exposes internal data and breaks encapsulation
* of the containing class; the annotation won't prevent its use from production code, developers
* won't even see warnings if their IDE doesn't support the annotation. It's better to provide
* proper API which can be used in production as well as in tests.
*/
WORKAROUND
If there are bodies of code or classes that I use specifically for testing and need to remove them at release I add a custom TODO using Android Studio (Not sure if other IDEs have the same functionality), follow the screenshot below and in the TODO tab at the bottom, you will see a filter for each custom TODO on the left. This is by no means the best way to do it, but I find it the fastest manual way to remove code on release.
P.S I know the patterns are all sorts of messed up in this screenshot.
I have created my own annotation type like this:
public #interface NewAnnotationType {}
and attached it to a class:
#NewAnnotationType
public class NewClass {
public void DoSomething() {}
}
and I tried to get the class annotation via reflection like this :
Class newClass = NewClass.class;
for (Annotation annotation : newClass.getDeclaredAnnotations()) {
System.out.println(annotation.toString());
}
but it's not printing anything. What am I doing wrong?
The default retention policy is RetentionPolicy.CLASS which means that, by default, annotation information is not retained at runtime:
Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. This is the default behavior.
Instead, use RetentionPolicy.RUNTIME:
Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.
...which you specify using the #Retention meta-annotation:
#Retention(RetentionPolicy.RUNTIME)
public #interface NewAnnotationType {
}
Having the default Retention of an annotation does not mean that you can not read it at run-time.
Since
Annotations are to be recorded in the class file by the compiler
but need not be retained by the VM at run time. This is the default behavior.
It is possible to access them reading the .class file directly
This can be accomplished by using the ASM library (handling some corner cases, of course).
Check out its excellent User guide. In particular section 4.2 Annotations.
You may want to refer to the Spring framework's handling of such annotations (it uses shaded asm dependency):
SimpleAnnotationMetadataReadingVisitor
AnnotationMetadataReadingVisitor (deprecated)