String constant reference as value of Annotation attribute causes compile error - grails

I am using my properties file to get the values for #Scheduled annotation attributes.I am able to get the values from properties file but when I tries to pass String constant reference to Annotation attribute then compile time exception is raised.
#Slf4j
#CompileStatic
class TestJobService {
static lazyInit = false
public static String jobInterval = getSomePropertiesFileValues?.fixedRateInMS instanceof String? getSomePropertiesFileValues.fixedRateInMS:'10000'
#Scheduled(fixedDelayString = TestJobService.jobInterval)
void executeEveryTenSeconds() {
def date = new Date()
println date.format('yyyy/MM/dd HH:mm', TimeZone.getTimeZone('IST'))
}
}
Attribute 'fixedDelayString' should have type 'java.lang.String'; but
found type 'java.lang.Object' in
#org.springframework.scheduling.annotation.Scheduled
Then I tried to use String to pass like:
#Slf4j
#CompileStatic
class TestJobService {
static lazyInit = false
#Scheduled(fixedDelayString = '${getSomePropertiesFileValues.fixedRateInMS}')
void executeEveryTenSeconds() {
def date = new Date()
println date.format('yyyy/MM/dd HH:mm', TimeZone.getTimeZone('IST'))
}
}
OR
public static final String jobInterval = getSomePropertiesFileValues?.fixedRateInMS instanceof String? getSomePropertiesFileValues.fixedRateInMS:'10000'
prevents the variable from being treated as an inline constant and compiler complains of not being inline constant.
I understand that using single quote '${getSomePropertiesFileValues.fixedRateInMS}'we can get compiler to know that I want GString behaviour. But I don't know is this a bug in Groovy or its a functionality which I need to implement in some other way to pass the string values as annotation attributes. Any lead or any help is highly appreciable.

Related

`nameof` operator in flutter

There is nameof operator in C#, it allows to get property name at compile time:
var name = nameof(User.email);
Console.WriteLine(name);
//Prints: email
It is not possible to use reflection in flutter and I do not want to hardcode names of properties i.e. to be used for querying SQLite tables. Is there any workaround?
***Currently I'm using built_value library.
For the archives, I guess, this isn't possible as Dart doesn't store the names of variables after compiling, and as you mentioned, Flutter doesn't support reflection.
But you can still hardcode responsibly by grouping your properties as part of the object that they belong to, like with JSON:
class User {
final String email;
final String name;
const User({required this.email, required this.name});
Map toJson() => {
"email": email,
"name": name,
};
}
Instead of remembering to type out "email" and "name" whenever you use User, just call User.toJson(). Then, when you want to rename your variables, you can use your IDE's "rename all", or just skim over your User class to quickly change all of the names without missing any.
I'm currently monitoring the progress on the dart:mirrors package, which offers some neat reflective properties and methods, though, I hadn't found a simple way to just get the name of a symbol like nameof() does.
Example:
import 'dart:mirrors';
class User {
final String email;
final String name;
const User({required this.email, required this.name});
}
void main() {
reflectClass(User).declarations.forEach((key, value) {
print(value.simpleName);
});
}
Output:
Symbol("email")
Symbol("name")
Symbol("User")
These are of type Symbol.
More here: https://api.dart.dev/stable/2.4.0/dart-mirrors/dart-mirrors-library.html
So, until they develop a nameof, I've created an extension on symbol:
extension SymbolExtensions on Symbol {
String get nameof =>
RegExp(r'"(.*?)"').firstMatch(toString())!.group(1).toString();
}
So, you could do:
print(reflectClass(User)
.declarations[#email)]!
.simpleName
.nameof);
Output:
email
It's a start. Dart is still growing.
You can use code generation.
The basic idea is to create a nameof annotation class and mark parts of your code with it. You also need to create a code generator that handles your annotated code. Look at the json_serializable package for an example and create your own code generator.
If you do not want to create your own generator, use a ready-made package nameof: https://pub.dev/packages/nameof
Short how-to with this package.
Mark your class with nameof annotation.
#nameof
class Car {
final double price;
final double weigth;
final int year;
final String model;
Car(this.price, this.weigth, this.year, this.model);
Car.sedan(double price, double weigth, int year)
: this(price, weigth, year, 'Sedan');
}
Run the code generator.
flutter pub run build_runner build
Then use the generated class, which will look something like this.
/// Container for names of elements belonging to the [Car] class
abstract class NameofCar {
static const String className = 'Car';
static const String constructor = '';
static const String constructorSedan = 'sedan';
static const String fieldPrice = 'price';
static const String fieldWeigth = 'weigth';
static const String fieldYear = 'year';
static const String fieldModel = 'model';
}
You can implement your own nameOf function:
String? nameOf(dynamic o) {
if (o == null) return "null";
try {
if (o is List) {
var first = o.length > 0 ? o[0] : null;
if (first != null) {
var elementType = nameOf(first)!;
Log.debug("nameOf: List<$elementType>");
if (!isMinified(elementType))
return "List<$elementType>";
}
} else {
Function? getTypeName = o.getTypeName;
if (getTypeName != null) return getTypeName();
}
} catch (e) {
Log.debug("ignored nameOf error: $e, falling back to o.runtimeType: ${o.runtimeType}");
}
return o.runtimeType.toString();
}
bool isMinified(String type) => type.startsWith("minified:");

Grails check if a class has a static variable with a particular value

I have a class in grails like:
class Autoresponder {
static String TYPE_NONE = "none"
static String TYPE_GETRESPONSE = "GetResponse"
static String TYPE_MAILCHIMP = "MailChimp"
static String TYPE_AWEBER = "AWeber"
static String TYPE_INFUSIONSOFT = "InfusionSoft"
static String TYPE_ICONTACT = "iContact"
static String TYPE_SENDY = "Sendy"
static String TYPE_ACTIVECAMPAIGN = "ActiveCampaign"
static String TYPE_API_ACTIVATE = "activate"
static String TYPE_ONTRAPORT = "ontraport"
//rest of code
}
I want to simply find that the above class has a static variable with value AWeber.
How do I do it? Is there a way to fetch all static user defined variables in a class(and thereby compare each variable's value with what I want)?
EDIT:
Due to some technical reasons, I can not change class definition.
Just iterate over all static fields looking for the one with the desired value. As in the following groovy script example
import static java.lang.reflect.Modifier.isStatic
class Autoresponder {
static String TYPE_NONE = "none"
static String TYPE_GETRESPONSE = "GetResponse"
static String TYPE_MAILCHIMP = "MailChimp"
static String TYPE_AWEBER = "AWeber"
static String TYPE_INFUSIONSOFT = "InfusionSoft"
static String TYPE_ICONTACT = "iContact"
static String TYPE_SENDY = "Sendy"
static String TYPE_ACTIVECAMPAIGN = "ActiveCampaign"
static String TYPE_API_ACTIVATE = "activate"
static String TYPE_ONTRAPORT = "ontraport"
}
def getStaticAttributeWithValue(Class clazz, Object searchedValue) {
clazz.declaredFields
.findAll{ isStatic(it.modifiers) }
.find { clazz[it.name] == searchedValue }
}
assert getStaticAttributeWithValue(Autoresponder, "AWeber") != null
assert getStaticAttributeWithValue(Autoresponder, "NonExist") == null
If the function returns null, there is no static field with that value, otherwise, it will be not null. (actually it will be a object of type java.lang.reflect.Field)
There is another way to fetch all static attributes in your class, that is using groovy MetaClass, but the idea is the same
def getStaticAttributeWithValue(Class clazz, Object searchedValue) {
clazz.metaClass.properties
.findAll{ it.getter.static }
.find { clazz[it.name] == searchedValue }
}
This way you will get a groovy.lang.MetaBeanProperty instead
The easiest way would be to use GrailsClassUtils.getStaticFieldValue to see if a Groovy class in Grails has a static property with a given value.
The above utility class has other methods that you may also find helpful.
Try to go with MetaClass. Something like (not tested... just an idea):
String val
if(Autoresponder.metaClass.static.AWeber){
val = Autoresponder.AWeber
}
With MetaClass you can also edit the methods and statics in there. It should also be faster than reflections

Cannot access domain property from Java class (in src folder)

I cannot access exploits property in domain class - Scenario , from my java class - MatchScenario , located in Grails src folder.
Already tried :
Explicit methods :
I have tried explicitly creating the get;set; but I get stackOverflow error since the setExploits() is called infinitely by itself for some reason.
Service to return the exploit field,
Though the service was created, it's never called on my fork-debug integration testing, so tests hangs with no exception
compilation error ->
Error:(59, 44) java: cannot find symbol
symbol: variable exploits
location: variable scenario of type core.Scenario
Java class, error on the inner loop ->
public class MatchScenario implements Callable{
private static final Logger LOG = Logger.getLogger(MatchScenario.class.getCanonicalName());
private List<Scenario> scenarioList
#Override
public List<Scenario> call() throws Exception {
LOG.debug( "*********************** schedule matcher called *****************************" );
if (scenarioList==null) {
LOG.debug("scenarioList not initialized ");
return null;
}
List<Scenario> scenarioAvailable = new ArrayList<Scenario>();
for (Scenario scenario : scenarioList){
for (Exploit exploit : scenario.exploits){
//println 'exploit -> '+exploit
if (!match( exploit.getExpression() ) ){
break;
}
}
//happens only when all scenario are available ( no break issued )
scenarioAvailable.add(scenario);
}
return scenarioAvailable;
}
private boolean match(String expression) {
return true;
}
}
Scenario domain object ->
package core
class Scenario {
String name
static belongsTo = [ Exploit ]
static hasMany = [ exploits : Exploit ]
static constraints = {
name nullable: false , maxSize: 32
}
}
You're confusing fields and properties. When you declare a property in a Groovy class, e.g. String name, the Groovy compiler converts that to a private field and adds a getter and a setter (unless you already defined one or both of them - it won't overwrite), in this case something like
private String name
public void setName(String name) { this.name = name }
public String getName() { return name }
It only does this if there's no scope modifier, so public String name and protected String name would both stay as defined.
One benefit of this is that you can later add logic to the getter and/or setter to modify the value, do some validation checks or computations, etc., and in Groovy you would still read and write to the name property since property access always calls the underlying setters and getters, and since properties like this are a Groovy-only thing that Java can't access, you would have been calling the setter and getter from Java all along, so you wouldn't need to recompile the Java classes that used the class.
Declaring a hasMany like yours creates an exploits property, effectively
Set<Exploit> exploits
and that property (added by a Grails AST transformation) is likewise converted to a private field with a getter and setter. So to get this working from Java, use the getter:
for (Exploit exploit : scenario.getExploits()) {

Grails : Overriding getter method in domain class

I can't override grails getter method and becoming crazy.
What I want is use a double value and a string value to get a formatted data, but when I'm typing my override method into String, the double value is null and when into double, it obviously get me an error because a String is returned !
I get a domain class like that :
class Project {
...
String currency
Double initialTargetAmount
...
}
First Override method (initialTargetAmount is null in this case) :
//#Override Comment or uncomment it does not make any change to the behaviour
public String getInitialTargetAmount() {
println "${initialTargetAmount} ${currency}" // display "null EUR"
"${initialTargetAmount} ${currency}" // initialTargetAmount is null
}
Second method :
//#Override Comment or uncomment it does not make any change to the behaviour
public Double getInitialTargetAmount() {
println "${initialTargetAmount} ${currency}" // display "1000.00 EUR"
"${initialTargetAmount} ${currency}" // Error : String given, Double expected
}
Any help is welcome.
Snite
Groovy has dynamic getters and setters.
So, initalTargetAmount field "creates" automatically a Double getInitialTargetAmount method. Which is why it works when you have the Double return Type. But when you set String, getInitialTargetAmount automatically refers to a field String initalTargetAmount which doesn't exist
Try changing the name of the method, for example getInitialAmountWithCurrency() and it will work. Maybe your best bet will be to override toString() method ^^
Your getter should be always the same type of your field, and it's noot a good approach to change the getter like this, because Grails (Hibernate internally) will understand that your object instance changed and will try to update it ( it will check the old and new values).
You're trying in fact is to have a String representation of your amount, so you have a couple of options to this:
1 - A new method
Creating a new method that returns String will not interfere in the hibernate flow and you can use it anywere.
class Project {
...
String currency
Double initialTargetAmount
...
String displayTargetAmount() {
"${initialTargetAmount} ${currency}"
}
}
2 - TagLib
Depending on your needs, you could create a TagLib to make this custom representations of your class. This can include html formatting.
class ProjectTagLib {
static namespace = "proj"
def displayAmount = { attrs ->
if(!attrs.project) {
throwTagErrro("Attribute project must be defined.")
}
Project project = attrs.remove('project')
//just an example of html
out << "<p>${project.initialTargetAmount} , ${project.currency}</p>"
}
}

grails: findallbyidinlist method

In my grails project, I've used the method Object.findAllByIdInList(), passing a list as parameter.
The code used is the following:
def allSelectedIds = ReceiptItem.findAllByIdInList(par)
In which the ReceiptItem is a domain class defined as follows:
class Receipt {
double totalAmount;
Date releaseDate;
int vatPercentage;
int discount;
Boolean isPayed;
Boolean isInvoice;
static belongsTo = [patient:Patient]
static hasMany = [receiptItems:ReceiptItem]
static constraints = {
receiptItems(blank: false)
patient(blank: false)
totalAmount(blank: false)
vatPercentage(blank: false, nullable: false)
}
}
and par is the list of ids defined as follows:
def par = params.list("receiptItemsSelected")
receiptItemsSelected is defined in the gsp page into the remoteFunction() as follows:
params: '\'receiptItemsSelected=\' + jQuery(this).val()'
The problem is that the line above throws the following exception:
java.lang.String cannot be cast to java.lang.Long. Stacktrace follows:
Message: java.lang.String cannot be cast to java.lang.Long
I don't understand why it is throwing this exception.
Thanks for your help
Probably list par has ids as String. Generally id for domain objects is stored as Long. Try this instead
ReceiptItem.findAllByIdInList(par*.toLong())
*Also make sure that id represented as string isNumber().
assert !'C'.isNumber()
assert '4'.isNumber()

Resources