How to ignore inner static classes in Jacoco when using Gradle - java

I know how to ignore classes defined in their own .java files, but not aware of how to ignore inner classes.
For example, I have class A with nested class B:
class A {
...
static class B {
...
}
}
jacocoTestReport keeps checking the coverage when I want to ignore them in jacoco.gradle file with this syntax(learned from this post: How to ignore inner/nested classes with JaCoCo?): (setFrom part is for later versions of Gradle, where classDirectories = files() is deprecated)
apply plugin: "jacoco"
jacoco {
toolVersion = "0.8.3"
}
jacocoTestReport {
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it,
exclude: [
"com/example/xxx/*",
"com/example/xxx/A\$.*B*"
])
}))
}
}
($ must be escaped, while in the post there is no need because he uses Maven when I use Gradle)
So, how can I ignore this inner class?

At last I found the answer with several trial-and-failure. Seems that the naming pattern follows compiled Java classes naming convention, as mentioned in the other post, and will not require the . between the outer class and the inner class. So, it should be like A$B. And, there may be some .class interfering(my guess), so I added A$B*(for other normal classes, last * is not needed).
So it becomes:
"com/example/xxx/A\$B*"
I hope there be some documentation about this pattern of exclusion. There is not, yet.

Related

Lombok getters/setters are not visible from my annotation processor

I did custom implementation of javax.annotation.processing.AbstractProcessor and it work.
But my processor do not found getters, setters and constructors which generated by Lombok.
Here my propceesor(do I need to create minimal example?):
https://github.com/hohserg1/ElegantNetworking/blob/1.12.2-annotation-processor/src/main/java/hohserg/elegant/networking/annotation/processor/ElegantPacketProcessor.java#L62
Example class:
ElegantPacket //my
#Value //lombok
public class Test implements ClientToServerPacket {
int some; //it visible
//int getSome() //generated by Lombok, it invisible
//public Test(int some) //generated by Lombok, it invisible
}
If you wish to run both Lombok and another annotation processor, then you should delombok your code and run your annotation processor on the result.
This is what the Checker Framework Gradle Plugin does, as explained in the Checker Framework Manual.
Explanation:
Most annotation processors either produce output (say, issue warnings) or generate new classes. Lombok is an annotation processor that modifies existing code. It does so by accessing internal APIs of the javac compiler (it also supports eclipsec). These manipulations cause javac to emit bytecode that contains Lombok's changes to your classes. However, those changes are invisible to earlier phases of the compiler, notably your annotation processor. Another way of saying all this is that Lombok does not play well with other annotation processors.
Ok, I solve this by using annotationProcessor of gradle dependency configuration:
dependencies {
//gradle 4.6+
annotationProcessor 'org.projectlombok:lombok:1.18.8', "io.gitlab.hohserg.elegant.networking:annotation-processor:2.8"
...
}
Also not all lombok changes visible from my annotation processor still. Changes of fields access modifiers is not visible, but it can be determine from lombok annotations. As example, #Value makes package-private fields to private.
Also plugin apt may be used on gradle less that 4.6
buildscript {
repositories {
...
maven { url 'https://plugins.gradle.org/m2/' }
}
dependencies {
...
classpath 'net.ltgt.gradle:gradle-apt-plugin:0.9'
}
}
dependencies {
apt 'org.projectlombok:lombok:1.18.8', "io.gitlab.hohserg.elegant.networking:annotation-processor:2.7"
...
}

How to ignore/exclude nested classes in generating JavaDocs via gradle for Android project

I am generating JavaDocs using gradle for my Android Project
task javaDocs(type: Javadoc) {
failOnError false
source = android.sourceSets.main.java.sourceFiles
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
classpath += configurations.compile
excludes = ['com/example/package1/**', 'com/example/package2**',
'com/example/package3/A\$B*']
}
The problem I am facing is that I need Class A to be present in the JavaDocs but want to ignore nested class B which is nested inside Class A
public class A { // Need to have this in JavaDocs
...
public static final class B { // Need to ignore this from JavaDocs
...
}
}
I am unable to come up with any pattern which can allow me to exclude class B in the gradle script mentioned above. Any help would be really appreciated.

Groovy AST transformation - How to compile java annotated class with Gradle and Intellij IDEA

I want to develop a Groovy AST transformation to add some methods on certain classes. So I write an annotation class and corresponding transformation class. Then I annotate a java class with my Groovy AST annotation.
When I compile the java annotated class with embedded groovy compiler (for example by this snippet: Class enhancedClass = new GroovyClassLoader().parseClass(new File("..."));), the transformation is performed and methods are added to the compiled class which is called enhancedClass in the snippet.
But I cann't compile the java class with Gradle groovy plugin and Intellij IDEA correctly.
QUESTION: Can everyone help me to working with Groovy AST transformation in Gradle and Intellij IDEA?
NOTE 1: I use Intellij IDEA 14 ultimate edition.
NOTE 2:
My Groovy AST classes and the java annotated class and my "build.gradle" file are somethings like the followings:
Annotation class:
#Retention(RetentionPolicy.SOURCE)
#Target(ElementType.TYPE)
#GroovyASTTransformationClass(classes = {MyASTTransformation.class})
public #interface MyAST {
}
and Transformation class:
#CompileStatic
#GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
public class MyASTTransformation implements ASTTransformation {
#Override
public void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
...
}
}
The java annotated class:
#MyAST
public class A {
...
}
The "build.gradle" file:
apply plugin: 'groovy'
sourceSets {
main {
groovy {
srcDirs = ['src/main/groovy', 'src/main/java']
}
java {
srcDirs = []
}
}
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.4'
}
I created my first custom AST transformation and I also ran into similar issues so sharing my limited experience. I'm using Groovy 2.4.7 and IntelliJ IDEA 2016.3.2. I was only able to use the custom transform annotation if:
It was created as a separate artifact (project) and another project that was using the annotation referenced it.
Ran a Groovy test script in the same project as the custom AST transformation code that ran a GroovyShell with Groovy code that used the custom annotation.
I had first attempted doing it in the same project but that didn't work. I believe it's because the AST transformation occurs at compile time. Here's my example:
AST transformation project
Annotation
#Retention (RetentionPolicy.SOURCE)
#Target ([ElementType.TYPE, ElementType.METHOD])
#GroovyASTTransformationClass (classes = [SqlAssistTransform])
#interface SqlAssist {
}
Transformation
#GroovyASTTransformation(phase=CompilePhase.SEMANTIC_ANALYSIS)
class SqlAssistTransform extends AbstractASTTransformation {
...
}
settings.gradle
rootProject.name = 'groovy-sql-transform'
build.gradle
...
group = 'com.company.groovy.transform'
version = '1.0-groovy-2.4'
description = 'Groovy AST transformation for SQL syntax'
...
Project using AST annotation
Annotated class
#SqlAssist
class Something {
...
}
Dependency example #1 - dependency on AST artifact from repository
build.gradle
...
dependencies {
...
// As long as your local repository (or remote repository) has the AST transformation project installed. i.e. Run '.\gradlew install' in AST project to install to local repository
compile group:'com.company.groovy.transform', name:'groovy-sql-transform', version: '1.0.0-groovy-2-4'
...
}
...
Dependency example #2 - dependency on AST project
build.gradle
...
dependencies {
...
compile project(':groovy-sql-transform')
...
}
...
settings.gradle
rootProject.name = 'project-name'
// Assumption that AST project lives at the same level as this project
include "groovy-sql-transform"
project(":groovy-sql-transform").projectDir = new File("../groovy-sql-transform")
Testing
I didn't create a proper unit test, but I did use the following to test and debugged in IntelliJ so I could look at the AST in different places in my AST transformation code. Example test Groovy script that I had within the AST transformation project:
new GroovyShell(getClass().classLoader).evaluate '''
import com.company.groovy.transform.SqlAssist
#SqlAssist
class Testing {
...
}
'''

Writing custom Lombok Annotation handlers

I want to write custom Lombok Annotation handlers. I know http://notatube.blogspot.de/2010/12/project-lombok-creating-custom.html. But the current lombok jar file does not contain many .class files, but files named .SCL.lombok instead.
I found, the .SCL.lombok files are the .class files, the build script of Lombok does rename them while generating the jar file, and the ShadowClassLoader is capable of loading these classes -- and the acronym SCL seems to come from this. It seems the reason for this is just to "Avoid contaminating the namespace of any project using an SCL-based jar. Autocompleters in IDEs will NOT suggest anything other than actual public API."
I was only able to compile my custom handler by
unpacking the contents of the lombok.jar
renaming the .SCL.lombok files to .class
adding the resulting directory to the compile classpath
In addition, to be able to use my custom handler, I needed to create a new fat jar containing both the lombok classes and my custom handler. The custom lombok class loader essentially prevents adding custom handlers in other multiple jars.
Is this the only way to extend Lombok? Or am I missing something?
I am using the following buildscript
apply plugin: 'java'
repositories {
jcenter()
}
configurations {
lombok
compileOnly
}
def unpackedAndRenamedLombokDir = file("$buildDir/lombok")
task unpackAndRenameLombok {
inputs.files configurations.lombok
outputs.dir unpackedAndRenamedLombokDir
doFirst {
mkdir unpackedAndRenamedLombokDir
delete unpackedAndRenamedLombokDir.listFiles()
}
doLast {
copy {
from zipTree(configurations.lombok.singleFile)
into unpackedAndRenamedLombokDir
rename "(.*)[.]SCL[.]lombok", '$1.class'
}
}
}
sourceSets {
main {
compileClasspath += configurations.compileOnly
output.dir(unpackedAndRenamedLombokDir, builtBy: unpackAndRenameLombok)
}
}
tasks.compileJava {
dependsOn unpackAndRenameLombok
}
dependencies {
compile files("${System.properties['java.home']}/../lib/tools.jar")
compile "org.eclipse.jdt:org.eclipse.jdt.core:3.10.0"
compile 'javax.inject:javax.inject:1'
lombok 'org.projectlombok:lombok:1.16.6'
compileOnly files(unpackedAndRenamedLombokDir)
}
In the meantime Reinier Zwitserloot created a new git-branch sclExpansionUpdate, that contains an updated version of the ShadowClassLoader:
ShadowClassLoader is now friendlier to trying to extend lombok.
Your (separate) jar/dir should have a file named
META-INF/ShadowClassLoader. This file should contain the string
'lombok'. If you have that, any classes in that jar/dir will be loaded
in the same space as lombok classes. You can also rename the class
files to .SCL.lombok to avoid other loaders from finding them.
I guess this did not yet make it into the main branch because it certainly has not been tested that much - I just tried it out for myself and it contains a little bug that prevents loading the required META-INF/services from extensions. To fix it you should replace two method calls to partOfShadow with inOwnBase:
[... line 443]
Enumeration<URL> sec = super.getResources(name);
while (sec.hasMoreElements()) {
URL item = sec.nextElement();
if (!inOwnBase(item, name)) vector.add(item); // <<-- HERE
}
if (altName != null) {
Enumeration<URL> tern = super.getResources(altName);
while (tern.hasMoreElements()) {
URL item = tern.nextElement();
if (!inOwnBase(item, altName)) vector.add(item); // <<-- AND HERE
}
}
I tested it with the above fix and it seems to work fine (not tested much though).
On a side note: with this new extension mechanism, it is now finally also possible to have the extensions annotation handlers and annotations in a different namespace than "lombok" - nice!
Using the input from this question and from the other answer (by Balder), we managed to put together a custom Lombok annotation handler: Symbok. Feel free to use that as a sample for writing your own.
BTW, instead of writing a custom Lombok handler, you could also implement a javac plugin instead -- it might be simpler.

Eclipse generates Java class filename conflict for inner classes

I have two top-level classes; each has an inner class with the same name:
**A.java**
public class A
{
}
class TestCase
{
}
**B.java**
public class B
{
}
class TestCase
{
}
My expectation is that I will wind up with four class files, including A$TestCase.class and B$TestCase.class, which is what I get when I compile from the command line. Eclipse, however, just creates TestCase.class, and declares that "The type TestCase is already defined" when I try to compile B.java.
Is there an Eclipse option that I can set to produce (what I believe is the standard) A$TestCase.class and B$TestCase.class?
Thanks.
By the way, I am using Luna:
Version: Luna Release (4.4.0)
Build id: 20140612-0600
Both versions of TestCase are top level classses. You need to create inner classes
public class A {
class TestCase {
}
}
It doesn't do this for me. It creates an A$TestCase.class and a B$TestCase.class, as it should.
But this is only when they're actually inner classes... in your case, they're not really inner classes at all.
TestCase is not an inner class as you might think, and this is why formatting code is essential when coding. check this

Categories

Resources