I'm trying to create a GroovyDSL script which references some external libraries. Here's my script:
import com.github.javaparser.ast.Node
import org.reflections.Reflections
def ctx = context(
ctype: 'groovy.util.ObjectGraphBuilder',
paths: ['com/example/scripts/.*'],
filetypes: ["groovy"]
)
Map<String, Class> candidateClasses = new Reflections(Node.packageName).getSubTypesOf(Node)
.collectEntries { Class type -> [(type.simpleName.uncapitalize()): type] }
contributor(ctx) {
candidateClasses.each { String methodName, Class type ->
method name: methodName, params: [props: "java.util.Map", closure: "groovy.lang.Closure"], type: type.name
}
}
Trying to enable it in Intellij, I'm getting:
startup failed: transformDslSyntaxgdsl: 1: unable to resolve class com.github.javaparser.ast.Node
# line 1, column 1.
import com.github.javaparser.ast.Node
Now, I have the proper external dependencies declared in pom.xml, the rest of the code that depends on them is working just fine. I've also put the script inside a source folder (which some other answers here suggested might be relevant).
I have seen some examples for GDSL reference Intellij types like PsiClass, which tells me the classpath for GDSL files seems to be different from the project classpath. Is there any way to make sure project dependencies are appended to that classpath?
I also tried using #Grape only to get this error. Adding Apache Ivy as a dependency doesn't help, because again, project dependencies don't seem to influence the GDSL classpath.
After a bit more digging, I found that it is pretty easy to modify the IDE's classpath itself.
All you need to do is to drop a dependency into Intellij installation directory's lib subfolder, and reference the jar inside classpath.txt.
Initially, I added the jars my GDSL depends on directly, but then I realized I could simply add a dependency on Apache Ivy to classpath.txt instead and #Grab annotations would start working.
Related
I'm building a Kotlin multiplatform library. One of the targets in this project is javascript. In the source set I have added a dependency like this:
val jsMain by getting {
dependencies {
implementation(npm("libphonenumber-js", "1.10.13"))
}
}
The gradle sync was successful, now I want to import the files in jsMain directory. How can I achieve this?
Add npm dependency with generateExternals as you already did
implementation(npm("libphonenumber-js", "1.10.13", generateExternals = true))
generateExternals = true triggers a tool called Dukat that generates Kotlin external declarations from the Typescript definition file of that npm module.
Once your project syncs, it would have externals folder under your shared module's build folder like shown below,
(Ignore kmp-lib-1621 in above image. That would be your module/library name instead)`
Now copy and paste these files in your project (jsMain source set) and remove generateExternal = true from your dependency otherwise it would generate this files everytime. (1) you would lose any manual change (2) if you update the library version then it can potentially break your project
You should be able to call generated external code from Kotlin code, whether you keep it in build folder or you pasted it in your project code.
Important Note: Dukat tool is experiemental and known to create externals that may not work 100% times. So remove all unnecessary code from external generated code so you only end up having few references of classes you want to use from the npm library. Do some trial and error and you would be fine.
Hope this helps!
You have to use js(IR) backend and generate externals
implementation(npm("libphonenumber-js", "1.10.13", generateExternals = true)).
I have a Gradle project with two subprojects. The parent does not contain any code; all the Kotlin code is in the two subprojects. All Gradle build files are defined in the Kotlin DSL.
Upon building, Gradle generates two JAR files, one in the build subfolder of each subproject. I believe this is the intended default behavior of Gradle. But this is not what I want.
I want to publish the JAR file of the parent project as a Maven artifact. Therefore, I need both subprojects to be included in one JAR file. How can I achieve this?
Note: On this web page, the author seems to achieve pretty much what I would need in this code snippet:
apply plugin: "java"
subprojects.each { subproject -> evaluationDependsOn(subproject.path)}
task allJar(type: Jar, dependsOn: subprojects.jar) {
baseName = 'multiproject-test'
subprojects.each { subproject ->
from subproject.configurations.archives.allArtifacts.files.collect {
zipTree(it)
}
}
}
artifacts {
archives allJar
}
However, this is defined in Gradle's native Groovy DSL. And I find myself unable to translate it into the Kotlin DSL. I tried to put a Groovy build file (*.gradle) besides the Kotlin build file (*.gradle.kts), but this led to a strange build error. I'm not sure if mixed build file languages are supported. Besides, I would consider it bad practice too. Better only define all build files in just one language.
Also, the example above pertains to the Java programming language. But I do not expect this to be a big problem, as both Java and Kotlin produce JVM bytecode as compile output.
More clarification:
I am not talking about a "fat JAR". Dependencies and the Kotlin library are not supposed to be included in the JAR.
I do not care if the JAR files for the subprojects are still getting built or not. I'm only interested in the integrated JAR that contains both subprojects.
The main point is getting the combined JAR for the binaries. Combined JARs for the sources and JavaDoc would be a nice-to-have, but are not strictly required.
I would use the Gradle guide Creating "uber" or "fat" JARs from the Gradle documentation as a basis. What you want is essentially the same thing. It's also much better than the Groovy example you found, as it doesn't use the discouraged subprojects util, or 'simple sharing' that requires knowing how the other projects are configured.
Create a configuration for resolving other projects.
// build.gradle.kts
val mergedJar by configurations.creating<Configuration> {
// we're going to resolve this config here, in this project
isCanBeResolved = true
// this configuration will not be consumed by other projects
isCanBeConsumed = false
// don't make this visible to other projects
isVisible = false
}
Use the new configuration to add dependencies on the projects we want to add into our combined Jar
dependencies {
mergedJar(project(":my-subproject-alpha"))
mergedJar(project(":my-subproject-beta"))
}
Now copy the guide from the docs, except instead of using configurations.runtimeClasspath we can use the mergedJar configuration, which will only create the subprojects we specified.
However we need to make some modifications.
I've adjusted the example to edit the existing Jar task rather than creating a new 'fatJar' task.
for some reason, setting isTransitive = false causes Gradle to fail resolution. Instead I've added a filter (it.path.contains(rootDir.path)) to make sure the Jars we're consuming are inside the project.
tasks.jar {
dependsOn(mergedJar)
from({
mergedJar
.filter {
it.name.endsWith("jar") && it.path.contains(rootDir.path)
}
.map {
logger.lifecycle("depending on $it")
zipTree(it)
}
})
}
I have created a library in kotlin using gradle init and following the prompts. It compiles and produces a jar file in lib/build/libs. I then have another project that needs to access functions in the library. through intelliJ, I add the dependency by going to Project Settings > Modules > Dependencies and adding the jar file. I then attempt to import the package defined in the library with import DemoLib where DemoLib is the name of the package (and the name of the library). This does not compile as it does not recognize the package name. I have also tried importing as a library rather than a jar, with the same results. How can I achieve the desired result?
EDIT: In case it helps here is the code:
Library:
package DemoLib
class Library {
fun someLibraryMethod(): Boolean {
return true
}
}
Client Code:
package DemoClientAppOne
import DemoLib.*
class App {
val greeting: String
get() {
return "Hello World!"
}
}
fun main() {
println(App().greeting)
}
Not terribly interesting, but the point is that DemoLib is an unresolved reference even after adding the jar as a dependency
You have three options
Combine two projects under same IDE project and use Gradle dependencies on project:
settings.gradle:
include 'project-lib'
build.gradle:
implementation project(':project-lib')
See https://docs.gradle.org/current/userguide/declaring_dependencies.html#sub:project_dependencies
Install the library into local repository and add it as a Gradle dependency:
apply plugin: 'maven'
then run gradle publishToMavenLocal
and add mavenLocal() repository in gradle.build file.
See How to install a compiled by Gradle jar into the local Gradle Repository files-2.1 instead of the Maven repository?
Use this jar as a flat library Gradle dependency (assuming this jar is located in the libs directory:
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
implementation name: 'lib-jar-name'
}
If DemoLib is a package,
you need to
import DemoLib.*
to import all its names into scope. Just import DemoLib wouldn't do anything. Or better,
import DemoLib.SomeClass
to import only one specific name. Actually, if you start typing SomeClass (assuming that's a name in your DemoLib package), IDEA should suggest adding the import.
Also, it's better to follow naming conventions from the beginning, and DemoLib is not a good package name:
Names of packages are always lower case and do not use underscores (org.example.project). Using multi-word names is generally discouraged, but if you do need to use multiple words, you can either simply concatenate them together or use camel case (org.example.myProject).
I am trying to follow the intructions for setting up intellij scala project to work with sbt. However, I am not finding the run/configuration described in intellij 2020.1. Based on this post I understand that the way this is configured has changed. However, that post describes how to make old project work. What do I do for new projects?
Steps to Reproduce
Create nice sbt project with idea.sbt already configured with mainRunner
sbt new tillrohrmann/flink-project.g8
this includes idea.sbt
lazy val mainRunner = project.in(file("mainRunner")).dependsOn(RootProject(file("."))).settings(
// we set all provided dependencies to none, so that they are included in the classpath of mainRunner
libraryDependencies := (libraryDependencies in RootProject(file("."))).value.map{
module => module.configurations match {
case Some("provided") => module.withConfigurations(None)
case _ => module
}
}
)
It also comes with a README.md that says:
You can also run your application from within IntelliJ: select the classpath of the 'mainRunner' module in the run/debug configurations.
Simply open 'Run -> Edit configurations...' and then select 'mainRunner' from the "Use classpath of module" dropbox.
Import project into intellij 2020.1
Now what? I cannot find a "Use classpath of module" dropbox in intellij 2020.1.
IntelliJ's Use classpath of module corresponds to the classpath of sbt's sub-project. To create a Run Configuration using the classpath of mainRunner project try
Run | Edit Configurations...
Click the plus button + to Add New Configuration
Select Application
Give it a name say WordCount
Under Main Class specify Scala class with main method, say, org.example.WordCount
Working directory should be the root of the project
Set Use classpath of module to mainRunner
JRE should be 1.8 or above
Note as an alternative to using mainRunner project you could also use root project but select the checkbox Include dependencies with "Provided" scope.
I am using local aar files for one of our projects and have below Query.
I have 2 libraries and 1 application.
2 libraries are:
1. TestLib2
2. TestLib1
1 Application is:
1. Test
I use a aar file created for TestLib2 and refer it using flatDir in TestLib1. I can access the functions present in TestLib2 without any problems.
Now I use a aar file created for TestLib1 and refer it using flatDir in Test. I can access only the functions present in TestLib1. For accessing TestLib2 i have to add it to Test application as one more Library.
So the dependency is like below:
Test
|_ TestLib1
|_ TestLib2
Is the above possible in case of aar files?
Also in settings.gradle file for TestLib1 i mention to include
include ':app', ':testlib2-debug'
Where app refers to the TestLib1
The build.gradle file doesnt really have any flavors as such and i dont even have any restriction of using them as jar's since its containing only the java piece of code.
Any help on the same is much appreciated.
BR,
Jayshil
Update 1:
I tried below as well in build.gradle of TestLib1 and Test.
Still no luck.
dependencies {
compile (name:'testlib2-debug', ext:'aar') {
transitive = true;
}
}
And for Test App
compile (name:'testlib1-debug', ext:'aar') {
transitive = true;
}
So i finally figured out a solution for this.
It works for 2 level dependency mentioned above.
Create a jar file for Test Lib 2.
task clearJar(type: Delete) {
delete 'build/outputs/loggingSDK.jar'
}
task makeJar(type: Copy) {
from('build/intermediates/bundles/release/')
into('build/outputs/')
include('classes.jar')
rename ('classes.jar', 'testlib2.jar')
}
makeJar.dependsOn(clearJar, build)
By using a the command
gradle makeJar
You would have got a testlib2.jar
Copy this into your TestLib1
Use command
gradle assemble
This would create debug and release version
Take the debug version and copy it in Test you would be able to call functions of TestLib1 which in turn calls function of TestLib2
Hope this may help someone looking for such solution