Gradle, overload extension setter - groovy

Given an extension registered in gradle as foo:
class Foo {
Project proj
void setProject( Project project) {
this.proj = project
}
void setProject( String project) {
// do stuff
}
}
How do I get:
foo {
project = ':random-project'
}
to call the string setter and not fail in setProperty of the decorated extension object due to GroovyCastException?
The reason for this question arose from this issue: https://github.com/Centril/gradle-plugin-robospock/issues/5

Since I don't see any better answer yet, I am trying to suggest a possible alternative.
If you can keep type of proj as a String in Foo and where you actually use the instance of Foo class, lookup the project using the findProject method on the project object available to your plugin.
class FooPlugin implements Plugin<Project> {
// ...
void apply(Project project) {
// ...
project.findProject(fooInstance.proj)
}
}
You may find more on findProject or project methods to locate a project by path at API Documentation
There might be a way to access current Project instance in your Foo class then you may use the overloaded setter.

This works in Gradle versions 2.0 and later which is likely due to the move from Groovy 1.x to 2.x. I'd suggest using a later version of Gradle if that is possible.

Luke Daley from Gradleware informed me that this is a limitation of the Groovy language: https://issues.apache.org/jira/browse/GROOVY-2500

Related

Groovy how can I build a custom library and use it in a project as dependency

I have a set of code procedures I use in a lot of places and I'm trying to basically move it to a library.
So I created my library with some unit test and everything was looking promising and at least working localy..
When I went to my project and deleted the files locally and then try to import them from my library as a dependency the code does not work.
I always get this kind of error
Class does not define or inherit an implementation of the resolved method abstract getProperty(Ljava/lang/String;)Ljava/lang/Object; of interface groovy.lang.GroovyObject.
I'm definitely not an expert on groovy but basically I use it in my Jenkins and Gradle for pipelines and some basic packaging or environment deployments.
I can show my class:
class ConsoleRow implements Comparable {
...
final Integer priority
final String rowStatus
final String message
final String rowReportClass
ConsoleRow(Integer priority, String status, String msg, String rowC) {
this.priority = priority
this.rowStatus = status
this.message = msg
this.rowReportClass = rowC
}
#Override
int compareTo(Object o) {
return this.priority <=> ((ConsoleRow) o).priority
}
The line that gives me the error is this actual compareTo when trying to do the "this.priority"
Caused by: java.lang.AbstractMethodError: Receiver class com.abc.insight.jenkins.ConsoleRow does not define or inherit an implementation of the resolved method abstract getProperty(Ljava/lang/String;)Ljava/lang/Object; of interface groovy.lang.GroovyObject.
at com.abc.insight.jenkins.ConsoleRow.compareTo(ConsoleRow.groovy:24)
at com.abc.insight.jenkins.ConsoleOutputHtmlBuilder.processOutput(ConsoleOutputHtmlBuilder.groovy:115)
at com.abc.insight.jenkins.ConsoleOutputHtmlBuilder.processOutput(ConsoleOutputHtmlBuilder.groovy)
at com.abc.insight.jenkins.ConsoleOutputHtmlBuilder.buildReport(ConsoleOutputHtmlBuilder.groovy:20)
at com.abc.insight.jenkins.ConsoleOutputHtmlBuilder$buildReport.call(Unknown Source)
at build_e548mc0tqjmi822clitlsycdk.runReport(C:\dev\repo\insight\insight-health-check\data-foundation\smoke-test\build.gradle:77)
The calling function is just trying to sort a list of those objects
List<ConsoleRow> outputRows = []
...
return outputRows.sort()
The part that gets me really confused is that if instead of importing the library as a dependency I just do this directly in this repo and put my sources in my buildSrc\src\main\groovy\com\abc\insight the code works fine...
So I really think it might be how I package and publish my library that might be wrong.
I'm really sure this is some basic error on my part because I never did a groovy library before but somehow I can't make it work.
It might be that my publication is just wrong, on my library side I'm using this plugins to do the publishing.
plugins {
id 'groovy'
id 'java-library'
id 'base'
}
publishing {
publications {
maven(MavenPublication) {
from components.java
}
}
}
I tried to change components.groovy but somehow it does not work.
Any ideas or tips, I think my question probably is showing some really lack of know-how on groovy but looking at the documentation and examples I could not figure it out.
Doing some debug in my IDE the compareTo that generates the exception looks like this.
public int compareTo(Object o) {
CallSite[] var2 = $getCallSiteArray();
return ScriptBytecodeAdapter.compareTo(this.priority, var2[0].callGroovyObjectGetProperty((ConsoleRow)ScriptBytecodeAdapter.castToType(o, ConsoleRow.class)));
}
I tried following this guide and code structure when doing moving the code to a library
https://docs.gradle.org/current/samples/sample_building_groovy_libraries.html
Thanks for any feedback
p.s: My code might look weird, I tried first to have everything with the def blablabla but I was having some issues with typecasting but I don't think this would be the reason for the problem I'm facing.
Anyway I got a look at the generated code in my IDE and I see a lot of get methods just no idea where they expected this getProperty from
Ok this was definitely a user error.
I am using distribution version of gradle 6.5.1
When I did the gradle init to bootstrap my project I was provided with the dependency of gradle groovy-all version 2.5.11
implementation group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.5.11'
I thought that was a mistake and just updated to the latest version.
implementation group: 'org.codehaus.groovy', name: 'groovy-all', version: '3.0.9'
Now the problem is that the project in which I'm using the library is also running with gradle 6.5.1 so probably this version missmatch between compiple and usage was causing the problem.
By reverting to the correct version suggested by gradle the problem is gone.

How to retain some of the interface methods' default implementations in the implementing class in C# 8.0?

One would think that in C# 8.0 you should be able to do the following (according to this (1st snippet)):
public interface IRestApiClient : IRestClient
{
...
Task<T> PostPrivateAsync<T>(string action, OrderedDictionary<string, object> parameters = null, DeserializeCustom<T> deserializer = null)
{
return QueryPrivateAsync(Method.POST, action, parameters, deserializer);
}
...
}
public class SpecificClient : ExchangeClient, IRestApiClient, IRestHtmlClient, ISeleniumClient, IWebSocketClient
{
}
The example above won't compile because the interface members need to be explicitly and wholly implemented (including the methods supplying the default logic)
So one would think that the following should work:
public interface IRestApiClient : IRestClient
{
...
Task<T> PostPrivateAsync<T>(string action, OrderedDictionary<string, object> parameters = null, DeserializeCustom<T> deserializer = null)
{
return QueryPrivateAsync(Method.POST, action, parameters, deserializer);
}
...
}
public class SpecificClient : ExchangeClient, IRestApiClient, IRestHtmlClient, ISeleniumClient, IWebSocketClient
{
...
public async Task<T> PostPrivateAsync<T>(string action, OrderedDictionary<string, object> parameters = null, DeserializeCustom<T> deserializer = null)
=> await ((IRestApiClient) this).PostPrivateAsync(action, parameters, deserializer);
...
}
Nope, it looks like this method is recursive (despite the upcast) and will cause our favorite Stack Overflow exception.
So my question is (abstracting from the fact that I could change the design in my example), is there a way of keeping the implementation for a specific method default, preferably without the necessity of resorting to hacky or Static Helper Extension methods? I could call static extension method in both interface and the class but it kind of defeats the purpose of this feature.
// EDIT
I must admit it confuses me and it appears I am missing something critical that is obvious to other people. I didn't provide additional info because I didn't consider my issue to be code specific. Lets look at this simple example (taken from the website I linked on the beginning of my post):
According to #Panagiotis Kanavos comment: No, default members don't need to be implemented (...) what I screenshoted should not be true. Can sb please enlighten me?
// EDIT 2
As you can see I am properly targeting .NET CORE 3.0 with C# 8.0.
ERRORS:
Interface method cannot declare a body
Interface member 'void CryptoBotCoreMVC.IDefaultInterfaceMethod.DefaultMethod()' is not implemented
To answer the question in the comments: I didn't specify LangVersion explicitly in the .csproj file.
// EDIT 3
The issue was ReSharper, see:
https://stackoverflow.com/a/58614702/3783852
My comment have been deleted, presumably by the owner of the answer so I'll write it here: the clue was the fact that there was actually no error numbers, but the compilation was blocked. It turned out that there is an option to block compilation when these errors occur in ReSharper.
It seems that in the end this is a possible duplicate, but getting to this conclusion was quite a journey :).
The issue is caused by ReSharper, reference:
https://youtrack.jetbrains.com/issue/RSRP-474628
It appears that the problem will be resolved in version v2019.3 and we currently have v2019.2.3. You can setup ReSharper to block compilation depending on issue severity, the workaround is to disable this feature for the time being.

Unable to resolve class inside static method

I have a groovy class "Utils.groovy" which contains the method "makeHttpCall()".
This is a summarized version of the method:
static String makeHTTPCall() {
...
request.setHeader(javax.ws.rs.core.HttpHeaders.AUTHORIZATION, authHeader)
...
}
The compiler complains:
Groovy:Apparent variable 'javax' was found in a static scope but
doesn't refer to a local variable, static field or class.
If I make the method non-static though, it will stop complaining;
String makeHTTPCall() {
...
request.setHeader(javax.ws.rs.core.HttpHeaders.AUTHORIZATION, authHeader)
...
}
this way it doesn't complain. Why does the compiler complain about this?
Note that the method runs with no problems; it is run as part of a Jenkins shared library.
Thanks!
EDIT: Using
import javax.ws.rs.core.HttpHeaders gives
Groovy:unable to resolve class javax.ws.rs.core.HttpHeaders
So that class is not resolvable by the compiler, but it is when run inside Jenkins.
You need to add the library that provides "javax.ws.rs.core.HttpHeaders" to your project's buildpath. Alternatively, you can use an #Grab to your class/script. This is probably not what you want in this case since Jenkins is providing that dependency at runtime.

Gradle / Groovy models

I'm trying to use gradle to build simple native application. The below is an example code from Gradle documentation of native plugins.
model {
components {
main(NativeLibrarySpec) {
sources {
cpp {
source {
srcDirs "src/main/cpp", "src/shared/c++"
include "**/*.cpp"
}
exportedHeaders {
srcDirs "src/main/include", "src/shared/include"
}
}
}
}
}
}
I have several questions:
What do model, component words mean? I read about the model rules, but I don't get the idea and new syntax. Model looks like the method invocation, but there is not such method in Project class. The same for components, where is it from?
The second questions is about syntax main(NativeLibrarySpec) { .. }. What does it mean? It looks like method invocation, but why do we use the NativeLibrarySpec interface name as a parameter?
Where from does cpp name go on? I see that NativeLibrarySpec has the sources method has prototype void sources(Action<? super ModelMap<LanguageSourceSet>> action) and what does ? super .. mean? I don't understand why do we use the name cpp? How can I find out this in documentation?
Gradle is a nightmare for me..

Gradle plugin for default properties

I am trying (and failing :) ) to create a gradle plugin that has a default set of versions for dependencies and can be overridden in the gradle.build file that is calling my plugin. Ideally something like the sudo-code below
MyDefaultPropertiesPlugin.groovy
project.versions.springBoot="1.0.0-RELEASE"
MyPlugin.groovy
project.apply plugin: MyDefaultPropertiesPlugin
compile("org.springframework.boot:spring-boot-starter-web:${project.versions.springBoot}")
build.gradle
versions.springBoot = "1.1.0-RELEASE"
project.apply plugin "my.plugin"
I attempted to do using extensions but ran into isssue's via the ordering when overriding. (versions doesnt exist)
I would greatly appreciate any advise on this, maven would be easy, but my gradle knowledge is still evolving :)
Thanks in advance for any insight!
Plugins have to defer accessing the build model until after build scripts have been evaluated. Easiest solution is to use project.afterEvaluate {}, but there are others. For more information, see answers to similar questions here or on http://forums.gradle.org.
Came up with a pretty workable if not perfect solution, I will update if i think of anything better, my gradle is at a learning level, so please commend if this can be improved.
This allows me to define a set of versions and clients to overwrite those versions with a simple property
MyDefaultVersionsPlugin.groovy
class MyDefaultVersionsPlugin implements Plugin<Project>{
project.extensions.create('versions', MyVersions, project)
}
class MyVersions{
String spring
String slf4j
public MyVersions (Project project){
spring = setVersion(project,'springVersion', 'x.x.x.x')
slf4j = setVersion(project,'slf4jVersion', 'x.x.x.x')
}
private static String setVersion(Project project, String name, String version){
if(project.hasProperties(name)){
return project.getProperties().get(name)
}
else {
return version
}
}
}
MyPlugin.groovy
project.apply plugin: MyDefaultVersionsPlugin
compile("org.springframework.boot:spring-boot-starter-web:${project.versions.spring}")
build.gradle
buildscript { ext { springVersion = 'x.x.x.x'} }

Resources