How to open auto generated file level class - kotlin

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>

Related

Using MaterialFX in IntelliJ

I've been trying to use MaterialFX (which is a JavaFX design library (like jFoenix)) in IntelliJ but I didn't succeed to do so. I've added the required dependency:
Also, I've added the requires org.glavo.materialfx.adapter; in module-info.java:
module org.example {
requires javafx.controls;
requires javafx.fxml;
requires com.jfoenix;
requires org.glavo.materialfx.adapter;
opens org.example to javafx.fxml;
exports org.example;
}
Does anyone have an idea how can I use this library because the author didn't really explain well how to do so. I would like to mention that it works perfectly in Scene Builder's latest version so I just wonder why it doesn't do so in IntelliJ.
Use Maven (or Gradle) for dependency management
You are using Maven (at least that is what the screenshot shows in Idea, though it could be Gradle making use of a Maven repository).
You should define the dependency as a maven dependency in your pom.xml (or build.gradle) then reimport the build file into Idea.
You should not manually set library dependencies in Idea.
Idea and Maven will recognize that you have a modular project and, when you have the dependency defined in Maven, they will automatically put the new dependent module on the modulepath for compilation and execution.
The maven artifact can be found by searching the maven repository:
https://search.maven.org/artifact/io.github.palexdev/materialfx/11.13.5/jar
The dependency info is:
<dependency>
<groupId>io.github.palexdev</groupId>
<artifactId>materialfx</artifactId>
<version>11.13.5</version>
</dependency>
The module-info for MaterialsFX requires VirtualizedFX. The VirtualizedFX module also needs to be on your module path. The pom.xml file for MaterialsFX has a includes a dependency on io.github.palexdev:virtualizedfx:11.2.6. So the dependent module will be accessible for your build and runtime automatically via Mavan and Idea's inbuilt integration with the Java Platform Module System.
Require the correct module name
The module name for the library is not org.glavo.materialfx.adapter, it is MaterialFX, so you should use:
requires MaterialFX;
NOT:
requires org.glavo.materialfx.adapter;
I recommend that you spend some time studying tutorials for your build tool and the Java Platform Module System.
Example app
Example was created by running the idea new JavaFX project wizard, then modifying the resultant project.
pom.xml
In addition to having a dependency for the MaterialFX library, you also need to have dependencies for both javafx-controls and javafx-fxml.
MaterialFX requires both of these transitively at build and runtime (even if you don't use fxml in your application).
The MaterialFX pom.xml does not have an explicit dependency configuration for JavaFX, so you need to define those dependencies in your project pom.xml (which you would want to do in any case to ensure that your application is using a specific JavaFX version).
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>material</artifactId>
<version>1.0-SNAPSHOT</version>
<name>material</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>18</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>18</version>
</dependency>
<dependency>
<groupId>io.github.palexdev</groupId>
<artifactId>materialfx</artifactId>
<version>11.13.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.9.0</version>
<configuration>
<source>18</source>
<target>18</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
module-info.java
module com.example.material {
requires MaterialFX;
exports com.example.material;
}
MaterialApplication.java
package com.example.material;
import io.github.palexdev.materialfx.controls.MFXButton;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class MaterialApplication extends Application {
#Override
public void start(Stage stage) {
stage.setScene(new Scene(new MFXButton("mfx")));
stage.show();
}
public static void main(String[] args) {
launch();
}
}

How to exclude an annotation from Kotlin AllOpen plugin?

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>

Maven2 & Groovy compilation error but not within Eclipse

He,
I am having a mixed Java / Groovy eclipse project.
Inside eclipse utilizing the groovy plugin everything compiles just fine. In addition I have set up my project to utilize Maven2. And still everything compiles and runs (tests) just fine within eclipse.
However, compiling the project outside eclipse, i.e. using Maven2 standalone gives me compiler errors! The project is devided into several sub-projects (parent / module). The Maven2 configuration seems to be OK cause some of the modules compile but actually one gives me an compiler error, like:
[ERROR] \Projects\X\rules\src\main\groovy\x\Normalizer.java:[18,25] normalize(java.util.List<java.util.Map<java.lang.String,java.lang.Object>>) in x.
x.util.RuleUtil cannot be applied to (java.util.List<java.util.Map<java.lang.String,?>>)
[ERROR] \Projects\X\rules\src\main\groovy\x\Statistics.java:[70,67] inconvertible types
found : capture#683 of ?
required: java.lang.String
Why is this code compiling within eclipse but not using standalone Maven2?
Thanks in advance,
/nm
The problem that you are facing is a stub generation problem. GMaven creates Java stubs for your Groovy files to compile against the remaining Java files. If your application is completely in Groovy, or there is no referencing from Java classes to Groovy classes, you can remove the <goal>generateStubs</goal> goal.
The Groovy-Eclipse compiler does not require stubs and so you are not seeing this issue inside of Eclipse.
If you do require cross referencing between Groovy and Java, I'd recommend using the groovy-eclipse-compiler plugin for maven. More information is here:
http://contraptionsforprogramming.blogspot.com/2010/09/where-are-all-my-stubs.html
With this, you will be sure that your compilation inside Eclipse and outside works exactly the same.
The Groovy Eclipse plugin uses the version of Groovy presents within the plugin folder of Eclipse (groovy-1.7.5).
Most probably, the version of Groovy referenced in your maven file is different. You can specify it thought in the gmaven-runtime:
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.3</version>
<configuration>
<providerSelection>1.7</providerSelection>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.gmaven.runtime</groupId>
<artifactId>gmaven-runtime-1.7</artifactId>
<version>1.3</version>
<exclusions>
<exclusion>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>1.7.5</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>generateStubs</goal>
<goal>compile</goal>
<!-- <goal>generateTestStubs</goal> -->
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>

Best way to get maven dependencies

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.

Using native dependencies inside Maven

A POM dependency contains native libraries (DLLs inside a JAR file). How do I programmatically look up the path of the downloaded JAR file so I can pass it into "java.library.path"?
Answering my own question: http://web.archive.org/web/20120308042202/http://www.buildanddeploy.com/node/17
In short, you can use the maven-dependency-plugin:unpack goal to extract the libraries into a known path, and pass that into java.library.path:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>compile</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.jdesktop</groupId>
<artifactId>jdic-native</artifactId>
<version>${jdic.version}</version>
<classifier>${build.type}</classifier>
<type>jar</type>
<overWrite>true</overWrite>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
Since System.load() can't load libraries from within a jar, you will have to use a custom loader which extracts the library to a temporary file at runtime. Projects With JNI discusses this approach and provide code for the custom loader.
Library loader
We now have our JNI library on the
class path, so we need a way of
loading it. I created a separate
project which would extract JNI
libraries from the class path, then
load them. Find it at
http://opensource.mxtelecom.com/maven/repo/com/wapmx/native/mx-native-loader/1.2/.
This is added as a dependency to the
pom, obviously.
To use it, call
com.wapmx.nativeutils.jniloader.NativeLoader.loadLibrary(libname).
More information is in the javadoc for
NativeLoader.
I generally prefer to wrap such things
in a try/catch block, as follows:
public class Sqrt {
static {
try {
NativeLoader.loadLibrary("sqrt");
} catch (Throwable e) {
e.printStackTrace();
System.exit(1);
}
}
/* ... class body ... */
}
An alternative would be to unpack the dependency, for example using dependency:unpack.
You can use the maven dependency plugin to copy the artifacts to a predefined path:
http://maven.apache.org/plugins/maven-dependency-plugin/examples/copying-artifacts.html
If the DLL is inside the JAR, then you will need to copy it out to a directory before it can be loaded. (JARs that include native libraries usually do this themselves.) If your JAR isn't doing this, then you can use Class.getResourceAsStream() and write this to a directory that you've added to the java.library.path.
For an example of this, see loadNativeLibrary in JNA. It uses this technique to load it's own library (a JNI library) from a JAR.