How to use Logger in a gradle buildSrc class? - gradle

So, when I do the naive thing and just use:
logger.info("something")
I get:
<myfile>.groovy: 52: Apparent variable 'logger' was found in a
static scope but doesn't refer to a local variable, static field or class.
Possible causes:
You attempted to reference a variable in the binding or an
instance variable from a static context.
You misspelled a classname or statically imported field.
Please check the spelling.
You attempted to use a method 'logger' but left out brackets
in a place not allowed by the grammar.
# line 52, column 9.
logger?.info("Resolving ${projectPath} to ${version}")
I tried many variants, like setting up a class variable in a constructor:
static private log = Logging.getLogger(MyClass)
This fails with Logging being found in a static scope...
What is the magic here?

Gradle User Guide, chapter 18 says you can just use SLF4j in your buildSrc. I had luck with the #Slf4j annotation on the class. For example:
import groovy.util.logging.Slf4j
#Slf4j
class YourClass {
def logIt(){
log.info 'This is logged in Gradle'
}
}

Related

How to use Kotlin's `is` operator in SpEL expression?

I have a simple sealed class
sealed class Target {
class User(val id: Long) : Target()
class City(val id: String) : Target()
}
that is used as a parameter of s Spring bean method. I'd like to cache the method via the #Cacheable conditionally only when the parameter is User.
#Cacheable(CACHE_NAME, condition = "#target is Target.User")
open fun getFeed(target: Target): Map<String, Any?> { ... }
However I get an error: '(' or <operator> expected, got 'is'
How can I use is in the condition string?
Thanks to Raphael's answer I was able to find out that
Instead of Kotlin's is there's Java's instanceof.
SpEL has a special syntax for using instanceof where you need to use a wrapper around the class: filterObject instanceof T(YourClass).
The fully qualified class name must be used for classes from any other package than java.lang.
The fully qualified name available on runtime for a class defined inside the body of a sealed class is <package>.<SealedClass>$<SubClass>. In my case it was net.goout.feed.model.Target$User.
Putting all this together yeilds this SpEL
#target instanceof T(net.goout.feed.model.Target$User)
As far as I know, SpEL is java-based, and Java does not have an operator called 'is'. The Java equivalent of 'is' is 'instanceof'. Since Java and Kotlin are interoperable and you can work with Kotlin classes in a Java context, #target instanceof FeedTarget.User should work fine.

What 'final' keyword next to the field stands for?

In a legacy code, I'm working with, I found the following thing:
#Autowired
final lateinit var controller: CustomController
what does this final keyword mean here?
In a Kotlin documentation I found a short description about final keyword that is blocking overriding of the methods in open classes but no information about fields. Also - the class within which I found the line is not open
A final property or a method in Kotlin prevents overriding of the field / method. That being said, Kotlin by default considers a property or a method/function to be final unless specified by the keyword open. In your case, the final keyword is redundant.
Here's a small demo test case to illustrate the same.
open class Parent {
open val someValue = 0
final val otherValue = 13 // redundant modifier 'final' warning in Android Studio
}
class Child : Parent() {
override val someValue = 5
// override val otherValue = 19 // compile error
}
There is an interesting problem called Fragile Base Class in OOP and why some languages like Kotlin prefer final by default.
What you have there is a property, not a field.
It looks just like a field, as it would in Java; but in Kotlin, it actually defines a public getter method, a public setter method, and a private backing field*.
So the final modifier applies to the accessor methods, preventing those from being overridden in a subclass.  (As you say, the backing field itself can't be overridden anyway.)
As Siddharth says, final is the default in Kotlin, so you usually wouldn't need to specify it, though there are a few situations in which it would be needed — e.g. if it were already overriding something, or you were using the all-open or kotlin-spring compiler plug-ins.  (The use of #Autowired suggests that this is a Spring module, which probably explains why final is needed here.)  In any case, your IDE would probably indicate where it's not needed, e.g. by showing it greyed-out.
(* Only the getter is necessary; the setter isn't generated for a val, and the backing field isn't generated if you override the accessor(s) and they don't refer to it.)

Reading Environment variable in SpringBootApplication [duplicate]

This question already has answers here:
Spring: How to inject a value to static field?
(5 answers)
Closed 3 years ago.
I have an environment variable RESOURCES_FOLDER. Which i want to read in a class inside my Springboot application
#Value("${RESOURCES_FOLDER}")
private static String resourcesFolder;
When I try printing the value it gives null instead of printing the actual path in my environment variable. Can someone please help me with this ??
Spring does not allow injecting values into static fields. You have a few options to circumvent this restriction:
Create a non-static setter. This is not a particularly good approach, as resourceFolder will be shared by all instances of a class. Nevertheless, you should be able to achieve it by:
public class SomeClass {
...
public static String resourcesFolder;
#Value("${RESOURCES_FOLDER}")
public void setResourcesFolder(String resourcesFolder) {
this.resourcesFolder = resourcesFolder;
}
...
}
Declare the field as non static. For this, ask yourself: do you really, really need the field to be static? Most of the time non-static field is good enough.
Create a separate #ConfigurationProperties class, declare fields as private non-static, create getters/setters for it and inject the class wherever you need the variable. This is a very composable and testable approach, which I would recommend, especially if you have quite a few related properties.
Alternatively, please refer to the other similar questions: 1, 2.
Add your environment variable name in the application.properties file by:
RESOURCE_FOLDER_PATH =${RESOURCES_FOLDER}
Here RESOURCES_FOLDER is the name of your environment variable.
Then access the environment variable in the java class by using #value annotation.
public class AccessEnvironmentVariable{
#Value("${RESOURCE_FOLDER_PATH}")
private String RESOURCE_FOLDER;
private void displayEnvironmentVariable(){
System.out.println("Your environment variable Resource Folder: "+RESOURCE_FOLDER);
}
}

Groovy override default call method

I have the following groovy class as part of my gradle plugin:
class MyClass {
final Expando someOptions
MyClass() {
someOptions = new Expando()
}
def call(Closure configure) {
configure.delegate = someOptions
configure.resolveStrategy = Closure.DELEGATE_ONLY
configure()
}
}
Now I want to user to have the ability to configure this class by adding extra properties to it, but those properties should be stored in someOptions.
I tried doing this in the class:
def call(final Closure configure) {
configure.delegate = someOptions
configure.resolveStrategy = Closure.DELEGATE_ONLY
configure()
}
The user of the plugin can do:
myClass {
hello='world'
}
However, gradle does not seem to understand that the hello property does not exist on the myClass instance but rather on someOptions within the class. Whenever I use the above, I get errors about hello not existing in the MyClass instance.
How do I do this? Is it possible?
FWIW, it works in the groovy console, but not in gradle.
Any classes you define in your plugin are not directly used in Gradle, but wrapped in proxy classes by Gradle. As an example,
Gradle will create a proxy class for the actual class implementation and adds (among other things) also a property setter method. The method has the name of the property and has a single argument of the same type as the property. It is different from the setProperty and getProperty methods already added by Groovy. For example if we have a task with a property with the name message of type String then Gradle will add the method message(String) to the proxy class. (Source)
This is the reason, why you can omit the assignment sign in Gradle scrips:
task myTask {
myProperty true // uses Gradle generated method
myProperty = true // uses Groovy generated setter
}
Gradle also adds a method similar to yours to allow the configuration of any object in the DSL:
myExtension {
// this works thanks to Gradle
}
Without this proxy method, it would be necessary to use the method with(Closure) from the Groovy language for any block:
myExtension.with {
// this works thanks to Groovy
}
It seems like this proxy method overrides the call(Closure) method of your example.
To solve this, you could use the Delegate annotation in Groovy on someOptions. This would make all its properties available to the MyClass instance. You could also register someOptions as convention on MyClass.
EDIT
You can see that your method is never called by comparing the stacktrace of your current example and a second stacktrace, after you changed the name of the call method and called it explicitly (you need to use another property to get the same exception).

Why sonar(JaCoCo) is asking me to test my packages?

I am trying to close some test holes in my application and found that JaCoCo sonar plugin is giving me a smaller coverage in my enums because it thinks I should test the Package names.
Why is that?
It's showing me a 97% coverage in one of my enums and displaying a red line on top of the package declaration like this, telling me to test it... it does that in all Enums and on Enums only.
I came here looking for the answer to this, and after some more digging I discovered that it's due to some static methods that can be found in the bytecode of the compiled enum class which Jacoco is expecting to be covered. After some experimentation, I came up with the following superclass to use for unit tests which are focused on enums, with JUnit 4. This resolved my coverage problems with enums.
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static org.junit.Assert.assertEquals;
public abstract class EnumTest {
#Test
public void verifyEnumStatics() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class e = getEnumUnderTest();
Method valuesMethod = e.getMethod("values");
Object[] values = (Object[]) valuesMethod.invoke(null);
Method valueOfMethod = e.getMethod("valueOf", String.class);
assertEquals(values[0], valueOfMethod.invoke(null, ((Enum)values[0]).name()));
}
protected abstract Class getEnumUnderTest();
}
And then use it like this:
public class TravelTypeTest extends EnumTest {
#Override
protected Class getEnumUnderTest() {
return TravelType.class;
}
// other test methods if needed
}
This is a rough first attempt - it doesn't work on enums that for whatever reason don't have any entries, and doubtless there are better ways to get the same effect, but this will exercise the generated static methods by ensuring that you can retrieve the values of the enum, and that if you pass the name of the first enum entry to the valueOf() method you will get the first enum entry back.
Ideally we'd write a test that searches for all enums in the packages under test and exercise them in the same way automatically (and avoid having to remember to create a new test class for each new enum that inherits from EnumTest), but I don't have many enums so I haven't felt any pressure to attempt this yet.

Resources