Can you please help me understand what are the typical use-cases in which one would use the runtime dependency configuration (provided by the Java plugin)?
In the Gradle user-guide, Table 23.5. Java plugin - dependency configurations, I can see that the runtime configuration is not used by any tasks - as opposed to e.g. the compile configuration which is used by the compileJava task.
What then is the runtime dependency useful for?
The runtime configuration is for libraries that are needed at runtime but NOT at compile time (For example JDBC drivers and SLF4J api implementations).
You could just add them to your compile configuration, but then they would be on the compile classpath and you would run the risk of accidentally introducing a compile dependency on something from the implementation rather than the api.
It is not for libraries that are 'provided' by a container - it is actually how you provide libraries to your app while making sure you haven't introduced a compile depencency on them.
Related
I don't really get why would Lombok require a special IDE related plugin to process dependencies when things Like Spring Boot (or any other compile-time annotation) do not require it. Is it because from a compile point of view the kind of changes that Lombok does are not in the same "page" as the kind of compile procesing that a maven dependency would be able to apply?
Many pom plugins have related M2E plugins, so I am inclined to believe that would be the way to go (unless someone at lombok hates M2E which would make sense)
Ok Log4j has a vulnerability between 2.0 and <2.15. I've been charged with updating the versions to 2.15 in some java applications we have. In digging in, this is pretty easy with gradle
compile 'org.apache.logging.log4j:log4j-api:2.15.0'
compile 'org.apache.logging.log4j:log4j-core:2.15.0'
compile('io.sentry:sentry-log4j2:5.4.3'){
exclude group: 'org.apache.logging.log4j'
}
solves the issue. But, everything can't be that simple right? OF COURSE! We have an application that references an internal artifact where the internal artifact source code DOESN'T EXSIST. It'd be easy to do the above in the internal artifact and publish a new version, but noooo. The internal artifact source requires spring boot, so updating the main application like this does not solve the issue.
compile('org.apache.logging.log4j:log4j-api:2.15.0')
compile('org.apache.logging.log4j:log4j-core:2.15.0')
compile('com.xxxx:xxxxx:0.0.1'){ <--
exclude group: 'org.apache.logging.log4j'
}
While the internal artifact does not include log4j with this setup, spring boot cannot find the reference to log4j because springboot is encapsulated inside the internal artifact.
I've been working at this for some time. I've tried implementation constraints. I've tried downloading the artifact, unzipping, and trying to decompile the class objects into java, but the decompiler was doing some optimization and I couldn't determine the target java version based on the decompiled classes. Which is scary and would require alot of testing before going into production.
How the hell do I either, make the aforementioned log4j version available to this mysterious artifact or how to I force the artifact to use a different version.
P.S. I've ran gradle dependencies and its 2.x -> 2.15. I've confirmed everything works fine with this upgrade.
P.P.S. The artifact is built with maven. I don't know if that matters and I don't think it does.
P.P.P.S. I've edited this a few times to improve clarity, if this is not your first time here, please re-read.
While adding new dependencies to android project especially in Android Studio in Dependencies there are three scope options Compile/Provided/APK.
What are the effects of choosing each one, when should we use them ? Besides what the name says.
EDIT:
"Properly handle 'provided' and 'package' scopes to do what they should be doing.
'provided' and 'package' cannot be used with Android Libraries, and will generate an error" .. this is from http://tools.android.com/tech-docs/new-build-system
provided - compile-time only dependency
package - package-time only dependency
compile - compile-time and package-time dependency
provided is commonly used for annotation processing based libraries. Usually these libraries are separated in two artifacts - "annotation" and "compiler". "compiler" is provided dependency because you do not need to use it in application, only for compilation; and "annotation" is compile dependency - it is used in application code and therefore compiles. Or generated code may require additional dependencies while your application may not. E.g. dagger dependencies configuration:
compile 'com.squareup.dagger:dagger:1.2.2'
provided 'com.squareup.dagger:dagger-compiler:1.2.2'
These properties come from maven scopes.
They simply indicate how to treat particular dependencies during each step of build process.
compile - a default approach, it simply means that all dependencies should be available at compile-time. Compile dependencies are available in all classpaths of a project. Furthermore, those dependencies are propagated to dependent projects. A compile-time dependency is generally required at runtime.
package - declares additional configuration for building an application. You can list plugins that add additional functionality to the build process.
provided - it means that runtime environment has these dependencies included. For example, when you look into android.jar library internals you will see java.lang.RuntimeException: Stub! in every method body.
That has some consequences:
You can develop Android applications locally, without having complete Android environment.
Your APK you must run it on an android device or an emulator because they provide implementation of these methods.
Your apps that reference the SDK classes will build properly, because the jar provides the class metadata.
Unless you use some library that provides artifacts (e.g. Robolectric), you have to run tests on your emulator/device.
provided and package cannot be used with Android Libraries, and will generate an error.
Here is how sourceSet looks like:
More info about build system: https://www.youtube.com/watch?v=LCJAgPkpmR0
An awesome article about Gradle: http://www.sinking.in/blog/provided-scope-in-gradle/
Xavier talks here about the APK scope.
in the Android plugin, The equivalent (sort of) of runtime is called apk. You can do
dependencies {
apk files('libs/foo.jar')
}
and it'll only get packaged but won't be on the compile classpath.
With gradle 6.5.1 provided gives the below error
Could not find method provided() for arguments [directory '....'] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
I used compileOnly to use the dependencies at only compile time and not to inlcude in the final build artifact
Let's say I have 10 Java EE projects(ear). Some of those depends on the package X (plain java package), which is very large. If I add it as compile dependency total project size would potentially grow as 10*(size of X package). I think runtime dependency option is the way to go. But have no idea make the package X available at runtime on containers such as JBoss. How to make plain java packages available at runtime on Java EE containers?
You are misunderstanding runtime dependency scope, when you mark a dependency runtime, it means maven will not add those dependencies in classpath during compilation
for example: if you have slf4j api and if you want to bind it with slf4j-simple at runtime you don't neeed slf4j-simple during compile time, this can be marked as runtime dependency
in your case, even if you don't need them during compile time you will have to pack them because you are building an EAR which needs to have all the dependencies, JBoss won't magically grab those dependencies for you
We are looking to revamp our Java build process on Eclipse. Currently we use Gradle! As a part of that effort we are looking at whether we are using Gradle in the best possible way. We use the Eclipse plugin for Gradle and declare our dependencies with compile. Unfortunately this adds a ton of transient dependencies with our generated Eclipse projects which is not desirable. These extra dependencies are only valid at runtime.
So, is there a way to declare a dependency ONCE in Gradle and have its compile dependency set to the first level of dependency and its runtime dependency set to the first level plus transient dependencies?
Currently we use the #jar syntax with compile which gives us the first level dependency for compile, but we still have to declare that dependency again for runtime. Not ideal because we have two places to go in order to update a dependency.
Is there a better way?
I assume you mean transitive dependencies.
If you only want direct dependencies to appear on Gradle's compile class path, your current solution seems reasonable. (In the future we want to have a more accurate compile class path out-of-the-box.) Potential improvements are to make the compile configuration non-transitive (rather than using #jar) or to write a plugin that provides a custom dependency syntax, thereby making the duplication between compile and runtime dependencies go away.
However, this won't help you with Eclipse, as Eclipse has no notion of separate compile and runtime class paths. The only way out is to make run configurations responsible for providing the runtime class path, but this might be difficult to set up (e.g. run configurations are often created on-the-fly), and Gradle doesn't have any out-of-the-box support for this. You could use the generic XML hooks of Gradle's Eclipse plugin to generate run configurations, but I'm not sure if the Eclipse Gradle integration would pick them up.
Due to these difficulties, most Eclipse developers put all runtime dependencies on the Eclipse project class path (regardless of whether they are using Gradle or not), despite the obvious disadvantages.
Our vision is that Gradle can one day act as the build engine for Eclipse. Once this happens, discrepancies between IDE and build tool (class paths, code generation, integration testing, etc.) will be a thing of the past. Gradle can already act as the build engine for NetBeans today, and soon also for IntelliJ IDEA (driven by the requirements for Android Studio).
While I certainly agree with #Peter that an overhaul of the Eclipse build process is a long-term goal, in the short term you may be able to accomplish what you want using Maven and m2eclipse. Whether the tradeoffs of moving to Maven are worth that extra control are entirely up to you.