Javadoc "cannot find symbol" error when using Lombok's #Builder annotation - java

I have a class looking as below :
#Data
#Builder
public class Foo {
private String param;
/** My custom builder.*/
public static FooBuilder builder(String _param){
return builder().param(_param);
}
}
I get the following error :
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:2.10.4:javadoc (default-cli) on project foo: An error has occurred in JavaDocs report generation:
[ERROR] Exit code: 1 - /home/workspace/foo/src/main/java/com/foo/Foo.java:34: error: cannot find symbol
[ERROR] public static FooBuilder builder(String _param)
[ERROR] ^
[ERROR] symbol: class FooBuilder
[ERROR] location: class Foo

Lombok is actually capable of filling out a partially defined builder class, so you can declare enough of the builder to make Javadoc happy and leave it at that. No need to delombok.
The following worked for me in this situation:
#Data
#Builder
public class Foo {
private String param;
// Add this line and all is good
public static class FooBuilder {}
}
Side note: that you can actually use this technique to add some customer builder methods, so it has perks. I like to overload builder methods when I have collections so I can items one at a time. There's probably already some technique that does that, but it's nice to know you can improve the builders manually.
Here's a common thing I like to do:
#Builder
public class Foo {
private final String command;
private final List<String> params;
private final boolean background;
public static class FooBuilder {
public FooBuilder params(final String... params) {
this.params = Arrays.asList(params);
return this;
}
}
}
In the above the params builder method has been customized to take var args. The other builder method will still be created by Lombok.

In order to solve this issue, I have to use Lombok's delombok feature (cf : https://projectlombok.org/features/delombok).
lombok doesn't cover all tools. For example, lombok cannot plug into javadoc ... which run on java sources. Delombok still allows you to use lombok with these tools by preprocessing your java code into java code with all of lombok's transformations already applied.
I did this using Maven by adding the following plugins :
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>1.18.0.0</version>
<configuration>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<outputDirectory>${delombok.output}</outputDirectory>
<addOutputDirectory>false</addOutputDirectory>
</configuration>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>delombok</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<configuration>
<sourcepath>${delombok.output}</sourcepath>
</configuration>
</plugin>

Update
If you use maven-javadoc-plugin 3.2.0+ you can configure it like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<doclint>none</doclint>
</configuration>
</plugin>
The doclint configuration will make javadoc plugin not throw an error anymore. It will also disable the lint but if you are ok with this probably the best way to go instead of delombok.
If you use any CI tool to build and compile your project you can create a separated job to check for javadoc lint.
For me disabling lint in the build is not a bad thing. Javadoc is important but shouldn't keep me from building my application just because I'm using Lombok.

Another solution to this would be to not include the BuilderClass in your imports. Instead just import the parent class and change your declaration of the builder type to parentClass.builderClass.
#Getter
#RequiredArgsConstructor
#Builder
public class Foo {
private final String param;
}
import com.Foo;
//import com.Foo.FooBuilder;
public class Bar {
public Foo newFoo(String paramValue) {
Foo.FooBuilder builder = Foo.builder();
return builder.param(paramValue)
.build();
}
}

Related

openapi generation - initialize objects

Iam using openapi-generator-maven-plugin for generating code from my yml files.
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>3.3.4</version>
When generating objects from the yml the generated code always generate objects and initilize them with null.
For example:
public class Foo {
#JsonProperty("bar")
private Bar bar = null;
}
Is there a way that the object is initialized with the object itself like:
public class Foo {
#JsonProperty("bar")
private Bar bar = new Bar();
}
Some snippets and links which can help You.
Plugin config in pom.xml:
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>4.2.2</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/docs/openapi/api.yml</inputSpec>
<generatorName>java</generatorName>
<templateDirectory>docs/openapi/template</templateDirectory>
</configuration>
</execution>
</executions>
</plugin>
Copy default templates e.g. from Java module of OpenAPI generator and put all mustache files inside some directory in Your project - check plugin configuration (in my case it is docs/openapi/template).
Find the file pojo.mustache which is a template to generate a POJO files.
You need to understand some basic Mustache syntax at this point. Find sych a fragment:
[...]
{{^isContainer}}
private {{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
{{/isContainer}}
[...]
Change to whatever You want, e.g.:
[...]
{{^isContainer}}
private {{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}}{{^defaultValue}}{{^isPrimitiveType}} = new {{datatypeWithEnum}}(){{/isPrimitiveType}}{{/defaultValue}};
{{/isContainer}}
[...]
This template snippet will generate new TypeYouWantToUse() parts for every non primitive datatype.
Be aware that this is just a simple example how to proceed further. There are many corner cases e.g. enum handling.
FUrther readings:
OpenApi generator
OpenApi generator templating documentation

Using a compile-time environment variable to configure RestApplicationPath

As stated in the documentation of rest-dispatch, the rest application path must be configured in the GIN module via a constant, here "/api/v1":
public class DispatchModule extends AbstractGinModule {
#Override
protected void configure() {
RestDispatchAsyncModule.Builder dispatchBuilder =
new RestDispatchAsyncModule.Builder();
install(dispatchBuilder.build());
bindConstant().annotatedWith(RestApplicationPath.class).to("/api/v1");
}
}
I would like to make the "/api/v1" constant be resolved at compile time, based on an environment variable set by the build system depending on the target environment (prod, dev, etc...), and on other criteria (the build artifact major version...).
The problem is I do not manage to rely on a compile time variable.
Neither TextResource/CssResource nor GWT's deferred binding won't help here, since GWT.create() cannot be used in GIN module. Another option I considered is using a custom Generator, but this seems to be too complex for this very simple need.
How do you solve this problem ?
If you use Maven as your build system, you could leverage the templating-maven-plugin to generate a Java class that will contain static variables defined in your POM file. That generated class will be used by your GWT code.
For example, you would want to populate a BuildConstants class template
public class BuildConstants {
// will be replaced by Maven
public static final String API_VERSION = "${myapi.version}";
}
and using a Maven property:
<myapi.version>v1</myapi.version>
that will be compiled to
public class BuildConstants {
// will be replaced by Maven
public static final String API_VERSION = "v1";
}
and you could reference those constants from within your DispatchModule:
bindConstant().annotatedWith(RestApplicationPath.class).to("/api/" + BuildConstants.API_VERSION);
Here's a sample config of the templating-maven-plugin that I use in a project:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
<version>1.0-alpha-3</version>
<executions>
<execution>
<id>filter-src</id>
<goals>
<goal>filter-sources</goal>
</goals>
<configuration>
<sourceDirectory>${basedir}/src/main/java-templates</sourceDirectory>
<outputDirectory>${project.build.directory}/generated-sources/java-templates
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
There's no reason you couldn't replace the bindConstant() with a #Provides method (or other bind().toProvider(), which would let you use a TextResource and/or deferred-binding, or whatever.
Asn an example (untested though), the code below uses JSNI to read the value from the host page, which makes it runtime dependent (rather than compile-time):
#Provides #RestApplicationPath native String provideRestApplicationPath() /*-{
return $wnd.restApplicationPath;
}-*/;
Following Thomas Broyer suggestion and Simon-Pierre, you could even bind different root .gwt.xml files depending on your maven profile. Then you choose the appropriate Gin module class where your constants are bound.
That is what we do inside the CarStore companion project of GWTP do do Form factors for example.

Version information for Java library, accessible at runtime

For supporting purposes I need to add a version and build identifier to our Java library. The library itself is a toolkit without user interaction which is used in different environments (stand alone Java applications, web applications, Eclipse applications, Maven dependency, ...).
What I want, is a class with some constants giving me the above described information (such as MyAppVersion.BUILD, ...), so that they can be shown e.g. in dialogs, command line output, etc. After my research, there seem to be the following approaches:
add versioning to file name, such as myLibrary-0.1.2.jar; not feasible in our case, since I have no control over the file name when deployed
add information to the MANIFEST.MF and read it programmatically, like described here. I'm not sure however, how robust this approach is in respect to different class loaders (Eclipse, OSGi, application servers, ...) and if the JAR file gets re-packaged, this information is lost
use a version.properties file holding the version, as described here and use a script during build to update the version.properties file
hard code the version information into the class directly and use a script to update this information
Are there any other approaches? The last option seems most "robust" to me, are there any objections against this variant? Is there a Maven plugin which would support updating this information in a MyAppVersion.java file during build?
I would suggest to use the templating-maven-plugin which is created exactly for such purposes.
You create at best a separate module which contains a template class like this (or within your module):
public final class Version {
private static final String VERSION = "${project.version}";
private static final String GROUPID = "${project.groupId}";
private static final String SVN = "${project.scm.developerConnection}";
private static final String SVN_BRANCH = "${scmBranch}";
private static final String REVISION = "${buildNumber}";
public static String getVersion() {
return VERSION;
}
public static String getGroupId() {
return GROUPID;
}
public static String getSVN() {
return SVN;
}
public static String getRevision() {
return REVISION;
}
public static String getSVNBranch() {
return SVN_BRANCH;
}
}
Which you simply put into src/main/java-templates folder plus an appropriate package name. Furthermore you configure the templating-maven-plugin like the following in your pom file:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
<version>1.0-alpha-3</version>
<executions>
<execution>
<goals>
<goal>filter-sources</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
This will generate a class Version which can be used by others and contains the given version. In the above template class you can use any property which is available in your build (things like JENKINS_ID etc.) or things your might define by yourself.
The result is that this class is compiled and packaged into your jar file.
Apart from that you can combine that with the buildnumber-maven-plugin to create the buildNumber which needs to be added to your pom file like this:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.2</version>
<configuration>
<revisionOnScmFailure>UNKNOWN</revisionOnScmFailure>
<getRevisionOnlyOnce>true</getRevisionOnlyOnce>
</configuration>
<executions>
<execution>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
</plugin>
The last option of hardcoding the version is the most robust which seems to be important to you.
If you build using ant, you can write a class (let's call it VersionGenerator) that will generate a java file with version:
package my.cool.package;
public interface Version {
String VERSION = "1.2.3";
}
Call VersionGenerator from ant
And then compile all your code and roll it into a jar. And your jar will contain a freshly generated and compiled Version.class!
VersionGenerator will have the logic of how to name and increase versions

Run tests from a #Category using Maven

I have looked at a few other SO questions like this and this. But those questions are pretty dated and I'm curious if there exists a new solution.
Here's what my setup looks like:
Category interface:
public interface FastTest{}
Category suite:
#RunWith(Categories.class)
#IncludeCategory(FastTest.class)
public class FastSuite{}
Sample test:
#Category(FastTest.class)
public class FastTests{
#Test public void assertOneFastTest(){}
#Test public void assertTwoFastTest(){}
}
Using maven, let's say I want to only run all my FastTest tests. Ideally, I would use the command
mvn test -Dtest.category=FastTest
or
mvn test -Dtest.suite=FastSuite
But I have not been able to get this working. Does anyone have any suggestions aside from using ClasspathSuite? Thanks.
You can do this from the surefire plugin, using the configuration for groups, but you need to specify the junit47 provider as well. The following works for me:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.11</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.11</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>default-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<groups>com.xxx.foo.CategoryClass</groups>
</configuration>
</plugin>
I think this was introduced fairly recently, so may not work in earlier versions of the plugin, pre 2.11. You need to specify the provider, otherwise it doesn't work. The groups should be the fully qualified name of the Category class. You can also specify an excludeGroups as well if needs be.
For more information, see Maven Surefire Plugin surefire:test.
Did a little more research and found no options so I ended up using ClasspathSuite. It turns out that it's not any different except that you cannot specify #Category at a class level, you have to annotate every method you want to categorize
Now, each category suite looks like this:
#RunWith(Categories.class)
#Categories.IncludeCategory(FastTest.class)
#Suite.SuiteClasses(AllTests.class)
public class FastSuite{}
You have to modify AllTests to look like this:
#RunWith(ClasspathSuite.class)
public class AllTests{}
For methods, it looks like this:
public class FastTests{
#Categories(FastTest.class)
public void assertOneFastTest(){}
#Categories(FastTest.class)
public void assertTwoFastTest(){}
}
Using maven, you can do the following command:
mvn test -Dtest=FastSuite -Dt3-chrome-path=%CHROME_DRIVER_HOME -Dwebdriver.chrome.driver=%CHROME_DRIVER_HOME

Run tests from inner classes via Maven

I have following tests structure:
public class WorkerServiceTest {
public class RaiseErrorTest extends AbstractDbUnitTest{
#Test
public void testSomething(){
}
...
}
...
}
It's done because I don't want to create a separate class file for every test case extending AbstractDbUnitTest.
The problem is that mvn test doesn't run test from my inner class. Is there is a way how to configure Maven to run such tests? Of course I can create methods in the parent class calling the inner class methods but I want a clearer way.
Yes, this is possible using the new (well, it's not new anymore) Enclosed runner (since JUnit 4.5) that runs all static inner classes of an outer class.
To use it, just annotate the outer class with #RunWith(Enclosed.class) and make the inner classes static.
#RunWith(Enclosed.class)
public class WorkerServiceTest {
public static class RaiseErrorTest extends AbstractDbUnitTest{
#Test
public void testSomething(){
}
...
}
...
}
And mvn test will run them.
I explain (a little more) the solution that I found...
Maven (AFAIK) uses by default the plugin "maven-surefire-plugin" to run any tests defined at your maven project. According to the documentation of this plugin, by default, it excludes tests that are enclosed at inner static classes (or at least it was with version that i'm using - 2.18.1).
So what i did was to put a empty exclude rule; resulting with a pom's build section like this:
<build>
<plugins>
...
<!-- ~~~~~~~~~~ SUREFIRE -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<excludes>
<exclude></exclude>
</excludes>
</configuration>
</plugin>
...
</plugins>
</build>

Categories

Resources