I am using Axon Framework, where I can annotate my domain classes with #Aggregate (which is meta-annotated with #Component from Spring). Then I have to apologize for every private method/field I have by marking them final explicitly.
I think in my case I am good with just marking the class open, so I would like to do it manually while excluding #Aggregate from the spring plugin but I can't find a way to do so.
workaround
According to the documentation, the spring plugin uses all-open under the hood by just listing Spring annotations, while supporting the meta-annotating. So, we do exactly that, but we don't specify list #Component, so in our code, we must use the stereotypes (repository, service, etc.). This way it doesn't pick up the #Aggregate:
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<!-- instead of 'spring' -->
<plugin>all-open</plugin>
</compilerPlugins>
<pluginOptions>
<!-- todo check up on https://stackoverflow.com/questions/56537496 -->
<!-- listing all spring annotations except #Component -->
<option>all-open:annotation=org.springframework.stereotype.Service</option>
<option>all-open:annotation=org.springframework.stereotype.Controller</option>
<option>all-open:annotation=org.springframework.data.repository.Repository</option>
<option>all-open:annotation=org.springframework.context.annotation.Configuration</option>
<option>all-open:annotation=org.springframework.boot.test.context.SpringBootTest</option>
<option>all-open:annotation=org.springframework.cache.annotation.Cacheable</option>
<option>all-open:annotation=org.springframework.transaction.annotation.Transactional</option>
<option>all-open:annotation=org.springframework.scheduling.annotation.Async</option>
</pluginOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
Related
I am working on a project where I have some Kotlin-Java interoperability issue.
What I discovered is that in Kotlin all class level functions are wrapped in an auto generated class which names are the same as fileName+kt. I want this class to be open. What decompiled bytecode shows is:
public final class ExampleAppKt
Is there a way to get rid of the final keyword?
According to kotlinlang (Actually all the information is from there. I recommend to read it for more detailed info):
Kotlin has classes and their members final by default, which makes it inconvenient to use frameworks and libraries such as Spring AOP that require classes to be open. The all-open compiler plugin adapts Kotlin to the requirements of those frameworks and makes classes annotated with a specific annotation and their members open without the explicit open keyword.
You can enable all-open plugin via Gradle:
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
}
}
apply plugin: "kotlin-allopen"
You can specify the annotation for classes to be compiled as open:
allOpen {
annotation("com.my.Annotation")
// annotations("com.another.Annotation", "com.third.Annotation")
}
If you use Maven, you can configure all-open as following:
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<!-- Or "spring" for the Spring support -->
<plugin>all-open</plugin>
</compilerPlugins>
<pluginOptions>
<!-- Each annotation is placed on its own line -->
<option>all-open:annotation=com.my.Annotation</option>
<option>all-open:annotation=com.their.AnotherAnnotation</option>
</pluginOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
I'm a bit confused. There is some documentation that says java 9 is "experimental":
https://mapstruct.org/documentation/stable/reference/html/#_using_mapstruct_on_java_9
And I found a post where a guy was having trouble in Java 10. So we are heading to java 11 and I want to know if Mapstuct will work in that environment. Specifically, will it generate the code at compile time AND does the generated code work there (I suppose the latter does).
Yes, it works on a Java 11 / Spring Boot 2 project at work, and we use Mapstruct without issues.
Yes, it is possible, although I struggled a bit with it while migrating a DropWizard project (1.3.7) to java 11. The configuration as proposed in the documentation (through the maven-compiler-plugin) didn't work for me (no error was shown, but the mapper class was not generated) so I had to use maven-processor-plugin v3.3.3.
Here is how I managed to do that:
Add the dependencies using <org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
<scope>provided</scope>
</dependency>
Then configure the plugin in the submodule as follows
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>3.3.3</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<processors>
<!-- list of processors to use -->
<processor>org.mapstruct.ap.MappingProcessor</processor>
</processors>
<outputDirectory>${basedir}/target/generated-sources-mappers</outputDirectory>
<compilerArguments>-source 11 -target 11</compilerArguments>
</configuration>
</execution>
</executions>
</plugin>
The outputDirectory is something specific to our project, but I leave there to highlight the fact that the xml tag changed from version 2.x of te plugin, in case you are migrating from that.
The compilerArguments portion was required because the plugin run javac passing java version 1.6 as default argument, which won't work if you are using lambda expressions or other new features from the language.
When compiling, make sure to pay attention to the output of the plugin, it should only show warnings, otherwise it won't generate you classes and you will get a generic ClassNotFound exception but the cause can be something not allowing your plugin to compile well.
[INFO] --- maven-processor-plugin:3.3.3:process
...
7 warnings
Also make sure you don't have any version of mapstruct library older than 1.3.0.Final in you classpath, that will also cause issues preventing classes from generating.
I used the following configuration for JDK11
<properties>
<mapstruct.version>1.3.1.Final</mapstruct.version>
<maven.compiler.version>3.6.1</maven.compiler.version>
</properties>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
Then mvn clean install will generate the impl classes in target\generated-sources\annotations
I have a Spring Roo multi module project. I noticed that after including the jar/module containing my domain model in another project, the aspects had not been woven leaving me with domain classes without any usable getters/setters.
How can I make sure that aspects generated by Spring roo are woven by the dependent project?
EDIT: In order to be able to use Roo's aspects from another project, one needs to include the aspectJ plugin in the dependent project. Note that compile time loading is not needed that way.
You need to include the aspectj maven plugin in the pom:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.4</version>
<!-- NB: do not use 1.3 or 1.3.x due to MASPECTJ-90 and do not use 1.4
due to declare parents issue -->
<dependencies>
<!-- NB: You must use Maven 2.0.9 or above or these are ignored (see
MNG-2972) -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
<!-- NB: force aspect compile before normal compile, required for 1.3+
see: MASPECTJ-13, MASPECTJ-92 -->
<phase>process-sources</phase>
</execution>
</executions>
<configuration>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
I only need to use this class org.apache.commons.io.FileUtils, and yet I'm downloading all commons Classes which I actually don't need, is there a way to say to maven download just FileUtils class? Not whole commons like from dependency below
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
is there a way to say to maven download just FileUtils class?
No. But depending on your exact use case, you could maybe use the Maven Shade Plugin to create an uber-jar and filter the content of the included dependencies:
Selecting Contents for Uber JAR
...
For fine-grained control of which
classes from the selected dependencies
are included, artifact filters can be
used:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.3.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>junit:junit</artifact>
<includes>
<include>junit/framework/**</include>
<include>org/junit/**</include>
</includes>
<excludes>
<exclude>org/junit/experimental/**</exclude>
<exclude>org/junit/runners/**</exclude>
</excludes>
</filter>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
Here, Ant-like patterns are used to
specify that from the dependency
junit:junit only certain
classes/resources should be included
in the uber JAR. The second filter
demonstrates the use of wildcards for
the artifact identity which was
introduced in plugin version 1.3. It
excludes all signature related files
from every artifact, regardless of its
group or artifact id.
But note that FileUtils depends on other classes:
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.FalseFileFilter;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter; // depends on org.apache.commons.io.IOCase
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.commons.io.output.NullOutputStream;
That you'll obviously need to include too.
Apache commons io has no dependencies to other apache commons projects. You get only commons io, no other commons libraries. That is one jar with about 100 classes, not very much.
You cannot get only one class into your project - this would propably also violating the license!
A look at FileUtils source also shows a lot of imports of other commons io classes. It will not work without the rest of the jar!
Use the dependency <exclusion> element
<dependency>
<groupId>sample.ProjectA</groupId>
<artifactId>Project-A</artifactId>
<version>1.0</version>
<scope>compile</scope>
<exclusions>
<exclusion> <!-- declare the exclusion here -->
<groupId>sample.ProjectB</groupId>
<artifactId>Project-B</artifactId>
</exclusion>
</exclusions>
</dependency>
to exclude those transitive dependencies that you don't need.
It is also a good practice to use mvn dependency:analyze-only and mvn dependecy:tree to understand how your depency graph is actually structured and what dependencies are you really using and not declaring and/or declaring and not using.
Regards.
I don't think so. The artifacts are packaged as jar files; you can't get them individually (that is, on a file-by-file basis). At least, not to my knowledge.
Also, think about it a little more - it is entirely possible that the FileUtils class has dependencies on other classes. But you can't really tell what they are without examining the source. That is information the user of the package does not need to know. You wouldn't want to figure out every other class that FileUtils uses (or what other classes the dependencies of FileUtils uses and so on and so forth). This is why the entire artifact is distributed as a discrete and self-contained entity. The artifact as a whole, if it is mavenized, will know what dependencies it needs and maven will go grab those for you as well.
I'm running a project that has a dependency on groovy 1.7-beta-1. The gmaven plugin uses groovy version 1.6 as a dependency. In my pom, I specify in the dependency management section the grooyv-all version as :
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>1.7-beta-1</version>
</dependency>
</dependencies>
</dependencyManagement>
Yet when I run maven in debug mode I see that groovy 1.6 is being used for a dependency to the gmaven plugin. I thought my dependency management section would override this so they all use 1.7-beta-1, but I'm getting errors due to the different groovy versions. any help here would be appreciated.
thanks,
Jeff
Here's a refined version of Pascal's answer. I upgraded the main plugin version to 1.2, the dependency to Groovy 1.7, and wrapped it all in a pluginManagement tag so that it will nicely leverage the inheritance model.
Keep in mind that the 1.3-SNAPSHOT of the GMaven plugin has already begun using the 1.7-rc2 Groovy provider.
<!-- I wrapped everything in a plugin management section so that this can be neatly inherited across all your poms -->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<!-- Notice I upgraded it to 1.2 -->
<!-- Details here http://repo1.maven.org/maven2/org/codehaus/gmaven/gmaven-plugin/1.2/gmaven-plugin-1.2.pom -->
<version>1.2</version>
<dependencies>
<dependency>
<groupId>org.codehaus.gmaven.runtime</groupId>
<artifactId>gmaven-runtime-1.7</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
Overriding a dependency used by a plugin is a nice ability that was actually introduced by Maven 2.0.9.
To do so, at least with a plugin that you are using as a normal build plugin - as opposed to a report which is not the case with the the gmaven-plugin so I won't cover this case here - simply add a dependency block inside the plugin block, like this (this is a sample so versions may be inaccurate):
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<goals>
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>1.7-beta-1</version>
</dependency>
</dependencies>
</plugin>
As long as the new version of the dependency is "API compatible" with the version the plugin was linked against, you should be ok. If not, then you'll obviously have to upgrade to a newer version of the plugin compatible with the new API (i.e. likely using it as dependency), which is what you did.
To make gmaven accurately picks the right runtime is by configuring the "providerSelection" value, e.g.
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<configuration>
<providerSelection>1.7</providerSelection>
</configuration>
FYI, for the groovy:providers mojo, these are the configurations it expects (I extracted them by debugging to org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(List, Stack, MavenSession, MavenProject) (look for XmlPlexusConfiguration):
<configuration>
<remoteRepositories implementation="java.util.List">${project.pluginArtifactRepositories}</remoteRepositories>
<project implementation="org.apache.maven.project.MavenProject">${project}</project>
<artifactRepository implementation="org.apache.maven.artifact.repository.ArtifactRepository">${localRepository}</artifactRepository>
<pluginArtifactMap implementation="java.util.Map">${plugin.artifactMap}</pluginArtifactMap>
<providerSelection implementation="java.lang.String">${gmaven.runtime}</providerSelection>
</configuration>
You need to add a similar 1.7 dependency to the dependencies of the plugin in a similarly structured <plugin> or <pluginManagement> section. Your dependency management section you are adding is proper, but does not affect the plugin dependencies. I'll try to review this reply and post an example later when I'm back at my desk.