Unable to resolve class inside static method - groovy

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.

Related

Test package dependencies within a module with ArchUnit

I have trouble formulating the following test with ArchUnit:
I want to ensure that all classes in a certain package only access classes outside of the application base package or within a certain sub package ("or" not "xor").
What I have got is:
#AnalyzeClasses(packages = "com.example")
public class ClassDependencies {
#ArchTest
static final ArchRule deps = classes.that()
.resideInAPackage("com.example.mymodule.some.package")
.should().onlyAccessClassesThat().resideOutsideOfPackage("com.example..")
.orShould().resideInAnyPackage("com.example.package1..", "com.example.package2..);
Problem is, that the or-condition should be within the onlyAccessClassesThat(). Above formulation fails if a class has both types of access, which I want to be valid.
How can I achieve what I want?
Thanks for any help on this...
You can specify provide the predicate as method argument and combine it with another predicate:
classes
.that().resideInAPackage("com.example.mymodule.some.package")
.should().onlyAccessClassesThat(
JavaClass.Predicates.resideOutsideOfPackage("com.example..")
.or(JavaClass.Predicates.resideInAnyPackage("com.example.package1..", "com.example.package2.."))
)

How to declare a constructor or extends a class of a groovy script?

I am working on a shared library for Jenkins, and I want to access some utilities methods between some classes, but not all of them, thus I have established some statements:
I would like to avoid using static methods, since it does not access pipeline steps directly, and passing the pipeline instance every call would be a pain;
I would like to avoid a singleton as well, or prefixing every method call with the util class' instance;
Since it is not supposed to be shared between all classes I would like to avoid putting every method as a file on vars/ special directory, but I would like a similar behavior;
Despite extending the class would be a anti-pattern, it would be acceptable, though I would like to avoid the verbose Java syntax for declaring the class the same name as the file, once it is implicit in groovy;
This question does solve my problem partially, although there are issues with serialization, I noted that when I use checkpoint and some build is resumed from some stage, the instance loses all extra methods.
This other question would have helped me fix the serialization issue, however the author seems the have solved the root cause of his problem using a way that is not the original question titled for.
Is there a way to extends a implicit script class in groovy without using the class NameOfFile extends SomeOtherClass { put every thing inside this block } syntax? And without working with inner-class?
Or else, is there a way to declare a constructor using the script groovy syntax analogue as the previous question?
Or even, is there a way to change the serialization behavior to install the extra methods again after unserializing?
Appendix
The script syntax works more-or-less like this:
Consider the content of file src/cicd/pipeline/SomePipeline.groovy:
package cicd.pipeline
// there is no need to wrap everything inside class SomePipeline,
// since it is implicit
def method() {
// instance method, here I can access pipeline steps freely
}
def static otherMethod() {
// static method, here it is unable to access pipeline steps
// without a instance
}
#groovy.transform.Field
def field
def call() {
// if the class is used as method it will run
this.method()
SomePipeline.otherMethod() // or simply otherMethod() should work
this.field = 'foo'
println "this instance ${this.getClass().canonicalName} should be cicd.pipeline.SomePipeline"
}
// any code other than methods or variables with #Field
// annotation will be inside a implicit run method that is
// triggered likewise main method but isn't a static one
def localVar = 'foo'
println "It will not execute on constructor since it is on run: $localVar"
println "Method: ${org.codehaus.groovy.runtime.StackTraceUtils.sanitize(new Throwable()).stackTrace[0].methodName}"
println "this instance ${this.getClass().canonicalName} should be cicd.pipeline.SomePipeline"
If I was going to use the Java verbose syntax I would have to wrap almost everything inside a class SomePipeline which is implicit in groovy, this is the script syntax I want to keep.
I realised that this.getClass().superclass.canonicalName when outside Jenkins pipeline is groovy.lang.Script and when inside pipeline is org.jenkinsci.plugins.workflow.cps.CpsScript and based on this resource I was able to elaborate the following solution:
abstract class CustomScript extends org.jenkinsci.plugins.workflow.cps.CpsScript {
public CustomScript() {
// do something here, it will always execute regardless
// serialization, and before everything
}
}
#groovy.transform.BaseScript CustomScript baseScript
That is it, worked as expected! Of course you can elaborate this solution better in order to reduce repeating and avoid inner-classes, but I will leave it for your imagination.

How add the #CompileStatic annotation to package scope in groovy

I would like to enforce static linking for a whole package in groovy. Static linking requires use of CompileStatic. I would like to avoid restating this on every class. How can I apply this as a package-level annotation. I have found no reference to package-level annotations in groovy.
Can you please provide a piece of code that shows how to apply the annotation to a package a.b.c?
This is untested, but I think it should be possible to create a nice combination of a configurationScript, a Source aware customizer and a AST transformation customizer explained in dsl docs.
something like:
withConfig(configuration) {
source(unitValidator: { unit -> unit.AST.classes.any { it.packageName== 'a.b.c' } }) {
ast(CompileStatic)
}
}

Not able to use variables defined in classes within groovy annotations

I am trying to port some code from the Dropwizard examples from java to groovy.
I see that within java, I can use the following code without any issues:
package com.example.helloworld;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
#Produces(MediaType.APPLICATION_JSON)
public class HelloWorldService{
}
However, with the groovy compiler ( both 1.8 and 2.0.6 ), the class fails to compile with a noClassFoundException around MediaType.APPLICATION_JSON
If I change this code to use the actual string value
#Produces('application/json')
public class HelloWorldService{
}
everything works perfectly.
Are there any differences between the way groovy resolves annotations and the way that java does?
For completeness, this is part of a gradle project and here is my build.gradle ( the file goes under src/groovy/com/example/helloworld )
apply plugin: 'groovy'
// Set our project variables
project.ext {
dropwizardVersion = '0.6.1'
}
repositories {
mavenCentral()
}
dependencies {
compile group: 'com.yammer.dropwizard', name: 'dropwizard-core', version: dropwizardVersion
groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.8.7'
}
The compilation error is:
Caused by: java.lang.RuntimeException:
java.lang.ClassNotFoundException:
com.sun.ws.rs.ext.RuntimeDelegateImpl ... 17 more Caused by:
java.lang.ClassNotFoundException:
com.sun.ws.rs.ext.RuntimeDelegateImpl at
org.gradle.api.internal.tasks.compile.TransformingClassLoader.findClass(TransformingClassLoader.java:47)
The problem is caused by an unfortunate limitation of the Groovy compiler, namely that it uses reflection to access classes on the compile class path. This may in turn trigger other classes to get loaded, which may not be available on the compile class path. Typically (but not always) these are runtime dependencies.
In the concrete case, the Groovy compiler loads javax.ws.rs.core.MediaType via reflection, which ultimately results in com.sun.ws.rs.ext.RuntimeDelegateImpl being loaded via Class.forName (triggered by a static initializer), which isn't on the compile class path. The solution is to put that class on the compile class path. (In the longer run, the solution is to fix the standalone Groovy compiler not to use reflection, and from what I know this is already in the queue.) If your module's transitive dependencies aren't an issue, the simplest way to achieve this is:
dependencies {
compile "com.sun.jersey:jersey-client:1.15"
}
I suspect that the Eclipse Groovy compiler doesn't have this problem because it doesn't use reflection to access the compile class path. I'd expect GMaven to blow up like Gradle, unless it is configured to use the Eclipse compiler (which isn't currently supported by Gradle).

Is it possible to automatically preload user classes into the groovy interpreter?

Is there any way to automatically load user classes in the groovy interpreter, the way System.out is automatically loaded (so you don't have to import System.out to use println)? I want to be able to write scripts that employ custom classes and run the scripts in the groovy interpreter without having to import all the classes all the time.
Yep, you just need to create a profile/rc file. Just create a file at ~/.groovy/groovysh.profile and put your imports in there. You'll also want to make sure that any additional classes you want to include are part of your CLASSPATH.
ex: ~/.groovy/groovysh.profile:
import org.apache.commons.lang.StringUtils
println "in groovysh.profile"
Then run groovysh and use a method from StringUtils:
% groovysh
in groovysh.profile
Groovy Shell (1.7.3, JVM: 1.6.0_20)
Type 'help' or '\h' for help.
---------------------------------------------------------------------------------------------------------------------------------
groovy:000> StringUtils.isWhitespace(" ")
===> true
groovy:000>
You can see that the import is in place (and that it also printed out the println I had in the profile. This example will only work if you've got the commons-lang jar file is in your classpath.
See the Groovy Shell page for more details.
Groovy adds some methods to Object, including methods like println and printf that you'd expect on printWriters. They implicitly use System.out. This is actually how groovy makes if feel like System.out is globally available.
If you want to import a set of classes by default, so they can be used without specifying the full package name, Ted's comment about groovysh.profile applies.
However, if you want a specific object, like System.out, global available so its methods can be called without referencing the object, then you can add some dynamic methods to Object. For example, to make the logging methods of the default global JDK logger globally available:
Object.metaClass.info = { String message ->
java.util.logging.Logger.global.info(message)
}
Object.metaClass.warning = { String message ->
java.util.logging.Logger.global.warning(message)
}
Object.metaClass.severe = { String message ->
java.util.logging.Logger.global.severe(message)
}
etc...
Once those methods are applied to the base Object metaClass, any object can call info("message") and have it logged, effectively making Logger.global available in the same way System.out is.

Resources