I have a set of Maven projects that I would like to migrate to SBT.
Tne only thing stopping me to do so, it's a project that is an Eclipse plugin, that has dependencies with Eclipse Birt.
The Tycho plugin for Maven, handles all the dependencies. This tool isn't available in SBT. I've found sbt-tycho plugin for SBT, but it looks like unmaintained (3 years with no activity).
Maybe I could build my Eclipse plugin with Maven, and the rest of projects with SBT. But don't know if this is possible.
Other alternative is to use Gradle, by means of the wuff plugin.
Related questions in StackOverflow:
How to build an eclipse plugin with sbt and sbt-osgi?
Can Apache Ivy handle dependencies in p2 repositories?
But I prefer SBT before Maven or Gradle, in order not to introduce yet another language besides Scala.
Is it possible to have all projects in SBT except the one that uses Tycho (Eclipse plugin)?. The Eclipse plugin project is a dependency of the main project, and it rarely changes.
Any ideas?
Update 1: additional information. Eclipse plugins use the p2 repository format for handling dependencies, instead of the standard Maven repository used for Gradle, Maven, Ivy and SBT. That's why special tools are needed. My custom Eclipse plugin has over 100 indirect p2 dependencies.
Update 2
pom.xml of my Eclipse plugin:
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>myCompany</groupId>
<artifactId>myPlugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
<properties>
<tycho.version>0.19.0</tycho.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>eclipse</id>
<url>http://download.eclipse.org/releases/kepler</url>
<layout>p2</layout>
</repository>
<repository>
<id>babel</id>
<url>http://download.eclipse.org/technology/babel/update-site/R0.11.1/kepler</url>
<layout>p2</layout>
</repository>
<repository>
<id>logback</id>
<url>http://logback.qos.ch/p2/</url>
<layout>p2</layout>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-maven-plugin</artifactId>
<version>${tycho.version}</version>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>target-platform-configuration</artifactId>
<version>${tycho.version}</version>
<configuration>
<resolver>p2</resolver>
<environments>
<environment>
<os>linux</os>
<ws>gtk</ws>
<arch>x86_64</arch>
</environment>
<environment>
<os>win32</os>
<ws>win32</ws>
<arch>x86</arch>
</environment>
</environments>
</configuration>
</plugin>
</plugins>
</build>
</project>
It appears that the support for Eclipse updatesite with OSGi bundles is already available in Ivy. It doesn't however mean that the resolver can be used directly in sbt (I have never read about it and seen it in use before so I might be mistaken).
There's a way to include any resolver of Ivy in sbt using externalIvySettings():
create the configuration files as you would for Maven (pom.xml) or Ivy
(ivy.xml and optionally ivysettings.xml). External configuration is
selected by using one of the following expressions.
There's Ivy settings (resolver configuration) with externalIvySettings and Ivy file (dependency configuration) with externalIvyFile.
My guess is that you might be quite successful leveraging the support. Just add externalIvySettings and/or externalIvyFile to build.sbt, and create ivy.xml in the top-level directory of the Eclipse plugin's project with a declaration of Ivy's Eclipse updatesite resolver.
You may want to explore the support with the following build.sbt:
externalIvySettings()
libraryDependencies += "bundle" % "org.eclipse.swt.cocoa.macosx.x86_64" % "3.100.1.v4234e"
Place ivysettings.xml in the project's top-level directory (alongside build.sbt):
<ivysettings>
<settings defaultResolver="chain"/>
<resolvers>
<chain name="chain">
<ibiblio name="central" m2compatible="true"/>
<updatesite name="eclipse-juno" url="http://download.eclipse.org/releases/juno" />
</chain>
</resolvers>
</ivysettings>
With the two files above I could update up to failing on some packages:
> update
[info] Updating {file:/Users/jacek/sandbox/eclipse-p2/}eclipse-p2...
:: loading settings :: file = /Users/jacek/sandbox/eclipse-p2/ivysettings.xml
[warn] module not found: package#org.eclipse.swt.accessibility2;[0.0.0,)
[warn] ==== central: tried
[warn] http://repo1.maven.org/maven2/package/org.eclipse.swt.accessibility2/[revision]/org.eclipse.swt.accessibility2-[revision].pom
[warn] -- artifact package#org.eclipse.swt.accessibility2;[0.0.0,)!org.eclipse.swt.accessibility2.jar:
[warn] http://repo1.maven.org/maven2/package/org.eclipse.swt.accessibility2/[revision]/org.eclipse.swt.accessibility2-[revision].jar
[warn] ==== eclipse-juno: tried
[warn] module not found: package#org.mozilla.xpcom;[0.0.0,)
[warn] ==== central: tried
[warn] http://repo1.maven.org/maven2/package/org.mozilla.xpcom/[revision]/org.mozilla.xpcom-[revision].pom
[warn] -- artifact package#org.mozilla.xpcom;[0.0.0,)!org.mozilla.xpcom.jar:
[warn] http://repo1.maven.org/maven2/package/org.mozilla.xpcom/[revision]/org.mozilla.xpcom-[revision].jar
[warn] ==== eclipse-juno: tried
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: package#org.eclipse.swt.accessibility2;[0.0.0,): not found
[warn] :: package#org.mozilla.xpcom;[0.0.0,): not found
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn]
[warn] Note: Unresolved dependencies path:
[warn] package:org.eclipse.swt.accessibility2:[0.0.0,)
[warn] +- bundle:org.eclipse.swt:[3.0.0,4.0.0)
[warn] +- bundle:org.eclipse.swt.cocoa.macosx.x86_64:3.100.1.v4234e (/Users/jacek/sandbox/eclipse-p2/build.sbt#L3-4)
[warn] +- default:eclipse-p2_2.10:0.1-SNAPSHOT
[warn] package:org.mozilla.xpcom:[0.0.0,)
[warn] +- bundle:org.eclipse.swt:[3.0.0,4.0.0)
[warn] +- bundle:org.eclipse.swt.cocoa.macosx.x86_64:3.100.1.v4234e (/Users/jacek/sandbox/eclipse-p2/build.sbt#L3-4)
[warn] +- default:eclipse-p2_2.10:0.1-SNAPSHOT
Another solution (I haven't tried yet) is to use the sbt-osgi-manager plugin, designed for this purpose. It is actively mantained.
I'll update this answer with my experiences.
UPDATE: it doesn't work for me in the first try.
The final solution is to use a standard Maven repository for the Birt plugins. This solution is good for the embedding the Birt runtime, but not for a complete RCP app.
Related
Upgraded Kotlin from 1.5 to 1.8 today: build fails in JDK 17 due to:
java.lang.reflect.InaccessibleObjectException: Unable to make field protected java.io.OutputStream java.io.FilterOutputStream.out accessible: module java.base does not "opens java.io" to unnamed module #2ba9f986
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)
at com.intellij.util.io.IOUtil.syncStream(IOUtil.java:217)
tried to add the following to my Maven configuration:
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<jvmTarget>${java.version}</jvmTarget>
<args>
<arg>"--add-opens java.base/java.io=ALL-UNNAMED"</arg>
</args>
</configuration>
</plugin>
but the problem is still there.
Official documentation does not seem to provide any info on this. Online search did not find much, apart from something about Gradle
Is there any Maven-plugin configuration to fix it? (ie build Kotlin 1.8 on JDK 17) or is that not supported?
For our Kotlin project build with Maven, We have the following file .mvn/jvm.config in the project folder. The content should be as follows:
--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.io=ALL-UNNAMED
I have a third party jar which is necessary for our project. It is not available on the central maven repository, so I used the maven-install-plugin to install the jar locally during a build. I tied the "install-file" goal to the "validate" phase, and this mostly works. The pom.xml file excerpt is below:
<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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>install-myartifact</id>
<phase>validate</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<file>${basedir}/lib/myartifact-1.2.3.jar</file>
<groupId>com.example</groupId>
<artifactId>myartifact</artifactId>
<version>1.2.3</version>
<packaging>jar</packaging>
<generatePom>true</generatePom>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>myartifact</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
However, there's a catch. Most of our developers and our Jenkins installation run "mvn clean install." The "validate" phase is not part of the "clean" lifecycle, and clean inexplicably requires all the dependencies be present to run. So the first time someone runs this build, it does not work.
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building MyModule
[INFO] task-segment: [clean, install]
[INFO] ------------------------------------------------------------------------
[INFO] [clean:clean]
[INFO] Deleting directory C:\svn\trunk\mymodule\target
Downloading: http://nexusserver.local:8080/nexus/content/groups/public/com/example/myartifact-1.2.3.pom
[INFO] Unable to find resource 'com.example:myartifact:pom:1.2.3' in repository central (http://central)
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed to resolve artifact.
Missing:
----------
1) com.example:myartifact:jar:1.2.3
Try downloading the file manually from the project website.
Then, install it using the command:
mvn install:install-file -DgroupId=com.example -DartifactId=myartifact -Dversion=1.2.3 -Dpackaging=jar -Dfile=/path/to/file
Alternatively, if you host your own repository you can deploy the file there:
mvn deploy:deploy-file -DgroupId=com.example -DartifactId=myartifact -Dversion=1.2.3 -Dpackaging=jar -Dfile=/path/to/file -Durl=[url] -DrepositoryId=[id]
Path to dependency:
1) com.example:mymodule:war:0.0.1-SNAPSHOT
2) com.example:myartifact:jar:1.2.3
----------
1 required artifact is missing.
for artifact:
com.example:mymodule:war:0.0.1-SNAPSHOT
from the specified remote repositories:
nexus (http://nexusserver.local:8080/nexus/content/groups/public)
[INFO] ------------------------------------------------------------------------
[INFO] For more information, run Maven with the -e switch
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 second
[INFO] Finished at: Thu Jun 09 11:01:24 EDT 2011
[INFO] Final Memory: 17M/247M
[INFO] ------------------------------------------------------------------------
If I were to run simply "mvn install", the jar is installed during "validate," and I can run "mvn clean install" in subsequent builds. However, our build server does not have that flexibility. I've considered the following:
Moving the phase to "pre-clean," but that assumes everyone always uses clean the first time. It wouldn't help if someone ran simply "mvn install."
Copying the execution, with one occurring during "pre-clean" and one occurring during "validate." This covers all the bases, but the copied code leaves a bad taste.
Ideally, I'd love some other option. Is it possible to run clean without dependencies? Or to run a plugin twice without having to fully copy the execution? Thanks!
I ran into a related issue, and I found this question when googling for a solution, so I'll note it here:
mvn clean fails in a multi-module project when there are missing dependencies within the same project, if plugins are invoked during clean.
We invoke the antrun-plugin during the clean phase in some modules, and because of that all dependencies need to be present in the maven repository, including the other modules in the same reactor, which in some cases have not been built yet (say you just bumped the project version, or you're starting off a new project).
This is a maven-antrun bug reported in https://issues.apache.org/jira/browse/MANTRUN-78 - which again leads back to a bug in maven core: https://issues.apache.org/jira/browse/MNG-3283.
My workaround was to provide the developers (and Jenkins) with an alternative way of doing clean (shell/bat script, ant script or some git/hg clean operation), and have them invoke this instead.
I would suggest a similar workaround for your team (or just set up up a shared maven repository internally in your team, use one of the developer machines if necessary).
It looks like you're using nexus. It might be easier to deploy the artifact to the nexus repo as opposed to having to maintain it with this project.
This is untested, but can you not ignore the error from the clean plugin's configuration? As in:
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<failOnError>false</failOnError>
</configuration>
</plugin>
(This is from Maven Clean Plugin : Ignoring Clean Errors)
Here is one more possibility.
Configure maven to skip clean phase and run clean during initialize. Have not tried this though.
The drawback of this is maven will always clean the output folders.
Usually the below pom config works for me. I've been successful in the past at adding my jar file's source to my projects as a dependency?
I have two jar files defined like so:
<dependencies>
<dependency>
<groupId>myGroup</groupId>
<artifactId>myJar</artifactId>
<version>4.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>myGroup</groupId>
<artifactId>myJar</artifactId>
<version>4.0</version>
<type>jar</type>
<classifier>sources</classifier>
</dependency>
</dependencies>
When I open up the myJar-4.0-sources.jar file from windows explorer view, I see all the java source files in it associated packages. But when I look in my eclipse project in my maven dependencies I only see xml files and no java files for myJar-4.0-sources.jar
BTW, regardless if I run the maven build inside eclipse or outside, it complains that there is no source code for classes that should be found in myJar-4.0-sources.jar.
BTW, this is a GWT compile.
Here is the actual error message:
[INFO] [gwt:compile {execution: default}]
[INFO] auto discovered modules [com.noesis.calendar.events.CalendarEvents]
[INFO] Loading inherited module 'com.noesis.commons.Commons'
[INFO] [WARN] Non-canonical source package: ./
[INFO] Compiling module com.noesis.calendar.events.CalendarEvents
[INFO] Validating newly compiled units
[INFO] [ERROR] Errors in 'file:/C:/dev/pouncil_projects/calendar-events/src/main/java/com/noesis/calendar/events/shared/model/Calendar
Event.java'
[INFO] [ERROR] Line 102: No source code is available for type com.noesis.commons.exceptions.CloneException; did you forget to inher
it a required module?
[INFO] [ERROR] Errors in 'jar:file:/C:/Documents%20and%20Settings/Tonte%20Pouncil/.m2/repository/com/noesis/commons/noesis-commons/0.0
.1-SNAPSHOT/noesis-commons-0.0.1-SNAPSHOT-sources.jar!/com/noesis/commons/domain/models/core/BaseEntityModel.java'
[INFO] [ERROR] Line 27: No source code is available for type com.noesis.commons.exceptions.CloneException; did you forget to inheri
t a required module?
[INFO] [ERROR] Errors in 'jar:file:/C:/Documents%20and%20Settings/Tonte%20Pouncil/.m2/repository/com/noesis/commons/noesis-commons/0.0
.1-SNAPSHOT/noesis-commons-0.0.1-SNAPSHOT-sources.jar!/com/noesis/commons/domain/models/core/DomainModelException.java'
[INFO] [ERROR] Line 6: No source code is available for type com.noesis.commons.exceptions.ApplicationException; did you forget to i
nherit a required module?
[INFO] [ERROR] Line 14: No source code is available for type com.noesis.commons.Context; did you forget to inherit a required modul
e?
[INFO] [ERROR] Errors in 'jar:file:/C:/Documents%20and%20Settings/Tonte%20Pouncil/.m2/repository/com/noesis/commons/noesis-commons/0.0
.1-SNAPSHOT/noesis-commons-0.0.1-SNAPSHOT-sources.jar!/com/noesis/commons/domain/models/core/PersistableBaseModel.java'
[INFO] [ERROR] Line 70: No source code is available for type com.noesis.commons.calendar.CalendarUtility; did you forget to inherit
a required module?
[INFO] [ERROR] Line 84: The method clone() is undefined for the type Object
[INFO] [ERROR] Line 91: No source code is available for type com.noesis.commons.exceptions.CloneException; did you forget to inheri
t a required module?
[INFO] Finding entry point classes
[INFO] [ERROR] Unable to find type 'com.noesis.calendar.events.client.CalendarEvents'
[INFO] [ERROR] Hint: Previous compiler errors may have made this type unavailable
[INFO] [ERROR] Hint: Check the inheritance chain from your module; it may not be inheriting a required module or a module may not b
e adding its source path entries properly
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR`
[INFO] [ERROR] Line 102: No source code is available for type com.noesis.commons.exceptions.CloneException; did you forget to inher
it a required module?
Does anybody have any idea why this is the case?
GWT looks for dependency sources in the same JAR as the compiled
class files. Since the library is under your control your best
course is to include the class files and the source files in the
same JAR. To do so add a <resource> to the <build> section of
the POM (assuming standard Maven source layout):
<project>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
</resource>
</resources>
</build>
</project>
GWT looks for dependency sources in the same JAR as the compiled class files. Your should include the class files and the source files in the same JAR. To do so add a <resource> to the <build> section of the POM:
<project>
<build>
<resources>
<!-- include the source files in our main jar for use by GWT -->
<resource>
<directory>${project.build.sourceDirectory}</directory>
</resource>
<!-- and continue to include our standard resources -->
<resource>
<directory>${basedir}/src/main/resources</directory>
</resource>
</resources>
</build>
</project>
I finally figured out my problem was. It was my .gwt.xml file. It was not referencing the GWT classes correctly. Not that I solved this, I believe the original way I wanted to reference my source library via the source jar file will work. Thanks.
I'm using both the assembly and jar plugins to deploy my application. I'm also using the jar plugin to help me generate the classpath in the manifest file using
<addClasspath>true</addClasspath>
While that seems to work, the problem comes when I try executing the jar (it has a proper main class specified) - it will fail to locate a library that's actually a transitive dependency. So my project A depends on project B, and project B depends on jar C. The assembly plugin will correctly zip up A, B, and C, but the jar plugin did not include C in the manifest, causing a ClassNotFoundException.
I don't see any options in maven-jar-plugin that lets me specify that transitive dependencies are required.
Am I doing it the right way? Anyone else managed to get transitive dependencies generated into the manifest? Maybe I'm doing something wrongly or out of order. Any help appreciated.
i tried to solve the mentioned problem. in my case it worked (maven-jar-plugin v2.2).
i've got a parent project called jarloading that has 3 childs:
main: with dependency to a
a: with dependency to b
b: with dependency to a
after calling
mvn package
publishing it using a deploy script containing
rm -r ~/Desktop/jarloading-bin
mkdir ~/Desktop/jarloading-bin
cp a/target/a-0.0.1-SNAPSHOT.jar ~/Desktop/jarloading-bin/
cp b/target/b-0.0.1-SNAPSHOT.jar ~/Desktop/jarloading-bin/
cp main/target/main-0.0.1-SNAPSHOT.jar ~/Desktop/jarloading-bin/
changing to directory
cd ~/Desktop/jarloading-bin
and running
java -jar main-0.0.1-SNAPSHOT.jar
it worked fine.
but actually the point is, how the classpath is listed in manifest file:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: rschmid
Build-Jdk: 1.6.0_07
Main-Class: Main
Class-Path: a-0.0.1-SNAPSHOT.jar b-0.0.1-SNAPSHOT.jar
pom.xml of main project:
...
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<index>true</index>
<manifest>
<mainClass>Main</mainClass>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>ch.fiftynine.lab</groupId>
<artifactId>a</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
...
pom.xml of a project:
...
<dependencies>
<dependency>
<groupId>ch.fiftynine.lab</groupId>
<artifactId>b</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
...
pom.xml of b project contains nothing really special.
and attached source code and binaries:
source code
binaries
I couldn't get the maven-jar-plugin to work, I had to use the maven-assembly-plugin.
Examples:
Brian Fox's Blog (this is the one I followed)
Maven Assembly Plugin Usage Guide
similar example by Scott Leberknight
I kinda managed to resolve by... not actually resolving it. I checked closer and still don't know why some transitive dependencies aren't getting picked up - it seems to skip of them and they end up not getting generated into the MANIFEST.
I dug around a bit and played with the maven-dependency-plugin. Surprisingly, configuring <attach>true</attach> and tying it to the assembly:assembly phase solved the classpath issue.
I have a project which has as maven dependency a jar file which includes a xml file where I stored my rules for checkstyle. I thought it would be ok to just use this configuration:
<configLocation>mycheckstyle.xml</configLocation>
My understanding is that the file should be searched on the classpath and my jar file is a Maven dependency so it should be found, however I get a resource not found exception.
Any suggestions?
Try adding a dependencies section to your plugin configuration.
E.g.,
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<dependencies>
<dependency>
<groupId>com.example.whizbang</groupId>
<artifactId>build-tools</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
See Maven Checkstyle Plugin - Multimodule Configuration for more information.
As explained in the Checkstyle plugin page,
configLocation :
Specifies the location of the XML configuration to use.
Potential values are a filesystem path, a URL, or a classpath resource.
I never did that on my project...
Are you sure that the JAR containing the XML file is in the classpath when the checkstyle plugin is starting?
I'm having a parent which specifies the checkstyle plugin and has in its resource folder the appropriate mycheckstyle.xml. I use the maven assembly plugin to make a jar of my parents resource folder and define that jar as a dependency in my child. So when the child inherits the checkstyle plugin + it's configuration from the parent it should be able to find the mycheckstyle.xml. I have followed the instructions on the checkstyle plugin page but it didn't work.
If you have a local maven repository for your self-created and compiled checks, please be aware to not forget defining
<repositories>
<repository>
<id>my local repository</id>
<url>file:${basedir}/.m2artifacts</url>
</repository>
<!-- ... -->
</repositories>
but also
<pluginRepositories>
<pluginRepository>
<id>my local repository</id>
<url>file:${basedir}/.m2artifacts</url>
</pluginRepository>
<!-- ... -->
</pluginRepositories>
otherwise the plugin dependency will just look in central maven repo but will not find your local JAR file with your check-classes