spring with kotlin scheduled annotation getting params from properties file - java

I am using spring 5 with kotlin and I have the following code
#Scheduled(cron = "${job.notification.expiring.x}")
fun notify() {
}
and in application.yml
job:
notification:
expiring.x: 0 0 12 1/1 * ?
On the line with the #schedulled, at cron parameter annotation Intellij says
An annotation parameter must be a compile-time constant.
How can I fix this, in Java the properties were loaded at run time.

You need to escape the $ character in Kotlin since this is used for String templates:
#Scheduled(cron = "\${job.notification.expiring.x}")
See the section on String templates at the bottom of this page:
https://kotlinlang.org/docs/reference/basic-types.html

Related

switsh and helpSwitch methods missing from org.refcodes.console.ConsoleSugar when upgrading to 2.x

I was using org.refcode.refcodes-console version 1.1.9. When upgrading to 2.0.4, it seems various methods no longer exist.
My scala code:
val theHelp = helpSwitch("Shows this help")
I get this error when compiling: not found: value helpSwitch
Same error when using switsh and StringOptionImpl.
How should I replace them when migrating from 1.x to 2.x for this maven artifact?
All 'switch' (aka switsh) methods in ConsoleSugar have been renamed to 'flag' in major version 2. So 'switsh' has been renamed to 'flag' and 'helpSwitch' has been renamed to 'helpFlag'.
For StringOptionImpl, use 'SpringOption' instead.
So in the example provided, it should now be:
val theHelp = helpFlag("Shows this help")
Also, for the switsh method you would need to add a 'aAlias' parameter as the third parameter. For example:
val block = switsh("-w", "--wait", "Wait at the end of the Program")
would need to be something like become
val block = flag("-w", "--wait", "wait", "Wait at the end of the Program")

SpEL (Spring) syntax for default value when property non-existant or equal to 0

I'm trying to set an Integer property to a default value of 1 if it either does not exist or if its current value is 0 and I can't for the life of me get the 0 comparison to work properly.
The original value (if set) will come in via the command line.
Here are the relevant line in my class:
#Configuration
public class AppConfig {
#Value("${${instance.procmultiplier} == 0 ? Integer.parseInt('1') : ${instance.procmultiplier}}")
public Integer procMultiplier;
}
I have tried numerous variations of the #Value annotation and at one point, I swear it recognized the 0 value, and I can't get back to that state. I was first trying to simply get it to recognize the 0 value and default to 1 and I was then going to try and insert a null-check.
Is there a way to do both all in the same annotation? One idea I had was to split the null-check and 0-check into two different properties, basically have procmultiplier=${instance.procmultiplier:1} in a properties file and then change the annotation to #Value("${${procmultiplier} == 0 ? Integer.parseInt('1') : ${procmultiplier}}") but nothing I try works.
My command is: mvn clean package && java -Dspring.profiles.active=json -Dinstance.procmultiplier=0 -jar target/MyApp-0.0.1-SNAPSHOT.jar.
The property ends up just being equal to whatever I set it to on the command line.
Any ideas on how to check for both non-existent and 0 and default to 1 if either is true, otherwise set to whatever comes in via command line?
It appears my problem was using ${...} instead of #{...}. Here is my solution using two different properties:
bootstrap.properties
procmultiplier=${instance.procmultiplier:1}
AppConfig.java
#Configuration
public class AppConfig {
#Value("#{${procmultiplier} == 0 ? 1 : ${procmultiplier}}")
public Integer procMultiplier;
}
Command Line:
mvn clean package && java -Dspring.profiles.active=json -Dinstance.procmultiplier=0 -jar target/MyApp-0.0.1-SNAPSHOT.jar
Also allows for a missing instance.procmultiplier parameter.
I still don't know how to do it all in one shot with 1 property though...
According to this post you should try
#Value("#{someBean.someProperty != null ? someBean.someProperty : 'default'}")
private String ternary;
This works for me in xml:
<bean id="myBean" class="myClass" >
<property name="myProp" value="#{systemProperties['a.b'] ?: '${a.b}'}"/>
</bean>
This will take from system properties if exist, otherwise from property file

Spring Rest Docs snippet template is ignored

I am attempting to be able to create custom snippet template for Spring Rest Docs documentation purposes. I have been following the reference guide
My first problem I ran into was in IntelliJ when creating a .snippet file in src/test/resources/org/springframework/restdocs/templates/asciidoctor/path-parameters.snippet as instructed by the guide. IntelliJ registers it as a jShell snippet file which from a quick glance is not the same as a AsciiDoc snippet. So I went into Settings -> Editor -> File Types and changed jShell Snippet from *.snippet to *.snippetOld. I then created a file type called Snippet and put it's pattern as *.snippet. This now fixes the problem that the snippet template is read as a jShell file. So the .snippet template I created no longer gets compile/validation errors.
But now when I run my mockMvc test after deleting the previous existing adoc files. The path-perameters.adoc file which should had used my custom template, if not use the default template, is now not generated at all.
In my mockMvc test I have the following
//Given
RestDocumentationResultHandler document = makeDocument("name-of-method");
document.document(
pathParameters(//do path parameters)
requestParameters(
parameterWithName("Month").description("The month requested").attributes(
key("type").value("integer"), key("constraints").value("more than 0 & less than 13.")
),
parameterWithName("Year").description("The year requested").attributes(
key("type").value("integer"), key("constraints").value("more than 1970 and less than current year")
)
),
responseField(//Do response fields)
);
// When
mvc.perform(get(REQUEST_PATH, USERID)
.contentType(MediaType.APPLICATION_JSON)
.param("month", "8")
.param("year", "2018"))
// Then
.andExpect(status().isOk())
.andDo(document);
And my snippet template is the following:
|===
|Parameter|Description|Type|Constraints
|{{parameter}}
|{{description}}
|{{type}}
|{{constraints}}
Could somebody point out what I've done wrong/different from the reference guide and how I could fix it to have my template working?
I suspect the reason you did not get output is that you confused path-parameters with request-parameters. Your documentation config specifies request parameters, but you customized path-parameters template
Here is the complete list of snippet templates:
curl-request.snippet
http-request.snippet
http-response.snippet
httpie-request.snippet
links.snippet
path-parameters.snippet
request-body.snippet
request-fields.snippet
request-headers.snippet
request-parameters.snippet
request-part-body.snippet
request-part-fields.snippet
request-parts.snippet
response-body.snippet
response-fields.snippet
response-headers.snippet
Source:
https://github.com/spring-projects/spring-restdocs/tree/master/spring-restdocs-core/src/main/resources/org/springframework/restdocs/templates/asciidoctor

Warning: File for type '[Insert class here]' created in the last round will not be subject to annotation processing

I switched an existing code base to Java 7 and I keep getting this warning:
warning: File for type '[Insert class here]' created in the last round
will not be subject to annotation processing.
A quick search reveals that no one has hit this warning.
It's not documented in the javac compiler source either:
From OpenJDK\langtools\src\share\classes\com\sun\tools\javac\processing\JavacFiler.java
private JavaFileObject createSourceOrClassFile(boolean isSourceFile, String name) throws IOException {
checkNameAndExistence(name, isSourceFile);
Location loc = (isSourceFile ? SOURCE_OUTPUT : CLASS_OUTPUT);
JavaFileObject.Kind kind = (isSourceFile ?
JavaFileObject.Kind.SOURCE :
JavaFileObject.Kind.CLASS);
JavaFileObject fileObject =
fileManager.getJavaFileForOutput(loc, name, kind, null);
checkFileReopening(fileObject, true);
if (lastRound) // <-------------------------------TRIGGERS WARNING
log.warning("proc.file.create.last.round", name);
if (isSourceFile)
aggregateGeneratedSourceNames.add(name);
else
aggregateGeneratedClassNames.add(name);
openTypeNames.add(name);
return new FilerOutputJavaFileObject(name, fileObject);
}
What does this mean and what steps can I take to clear this warning?
Thanks.
The warning
warning: File for type '[Insert class here]' created in the last round
will not be subject to annotation processing
means that your were running an annotation processor creating a new class or source file using a javax.annotation.processing.Filer implementation (provided through the javax.annotation.processing.ProcessingEnvironment) although the processing tool already decided its "in the last round".
This may be problem (and thus the warning) because the generated file itself may contain annotations being ignored by the annotation processor (because it is not going to do a further round).
The above ought to answer the first part of your question
What does this mean and what steps can I take to clear this warning?
(you figured this out already by yourself, didn't you :-))
What possible steps to take? Check your annotation processors:
1) Do you really have to use filer.createClassFile / filer.createSourceFile on the very last round of the annotaion processor? Usually one uses the filer object inside of a code block like
for (TypeElement annotation : annotations) {
...
}
(in method process). This ensures that the annotation processor will not be in its last round (the last round always being the one having an empty set of annotations).
2) If you really can't avoid writing your generated files in the last round and these files are source files, trick the annotation processor and use the method "createResource" of the filer object (take "SOURCE_OUTPUT" as location).
In OpenJDK test case this warning produced because processor uses "processingOver()" to write new file exactly at last round.
public boolean process(Set<? extends TypeElement> elems, RoundEnvironment renv) {
if (renv.processingOver()) { // Write only at last round
Filer filer = processingEnv.getFiler();
Messager messager = processingEnv.getMessager();
try {
JavaFileObject fo = filer.createSourceFile("Gen");
Writer out = fo.openWriter();
out.write("class Gen { }");
out.close();
messager.printMessage(Diagnostic.Kind.NOTE, "File 'Gen' created");
} catch (IOException e) {
messager.printMessage(Diagnostic.Kind.ERROR, e.toString());
}
}
return false;
}
I modified original example code a bit. Added diagnostic note "File 'Gen' created", replaced "*" mask with "org.junit.runner.RunWith" and set return value to "true". Produced compiler log was:
Round 1:
input files: {ProcFileCreateLastRound}
annotations: [org.junit.runner.RunWith]
last round: false
Processor AnnoProc matches [org.junit.runner.RunWith] and returns true.
Round 2:
input files: {}
annotations: []
last round: true
Note: File 'Gen' created
Compilation completed successfully with 1 warning
0 errors
1 warning
Warning: File for type 'Gen' created in the last round will not be subject to annotation processing.
If we remove my custom note from log, it's hard to tell that file 'Gen' was actually created on 'Round 2' - last round. So, basic advice applies: if in doubt - add more logs.
Where is also a little bit of useful info on this page:
http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/javac.html
Read section about "ANNOTATION PROCESSING" and try to get more info with compiler options:
-XprintProcessorInfo
Print information about which annotations a processor is asked to process.
-XprintRounds Print information about initial and subsequent annotation processing rounds.
I poked around the java 7 compiler options and I found this:
-implicit:{class,none}
Controls the generation of class files for implicitly loaded source files. To automatically generate class files, use -implicit:class. To suppress class file generation, use -implicit:none. If this option is not specified, the default is to automatically generate class files. In this case, the compiler will issue a warning if any such class files are generated when also doing annotation processing. The warning will not be issued if this option is set explicitly. See Searching For Types.
Source
Can you try and implicitly declare the class file.

Gradle - Java Project - Generic For Loop

I have a very simple generic for loop that is causing problems when I attempt to build the project using gradle:
for(TaskAttribute taskAttribute:task.getAttributes())
{
...
}
Task.java
protected final Set<TaskAttribute> attributes = new HashSet<TaskAttribute>();
public Set<TaskAttribute> getAttributes(){return(attributes);}
The error I am getting is that the for loop is getting Object, but requries TaskAttribute. I have my sourceCompatibility set to 1.6. Am I missing something else?
In groovy you can do for loops one of two ways.
task forLoopTest {
// print numbers 8 to 19 inclusive
for (x in 8..19) {
println 'this is run '+x
}
// print numbers 0 to 4
println 'now some groovy'
for(int i = 0;i<5;i++) {
println i
}
}
Run on CLI:
$ gradle forLoopTest
This should out put.
this is run 8
this is run 9
this is run 10
this is run 11
this is run 12
this is run 13
this is run 14
this is run 15
this is run 16
this is run 17
this is run 18
this is run 19
0
1
2
3
4
The basic set up for the enhanced for loop is :
for(<Object_Type> <Object_Name> : <Collection_Name>)
I am not sure what task.getAttributes() returns or what task is, but if you have a Collection( a Set) called attributes you should just change your loop to this:
for(TaskAttribute taskAttribute : attributes)
{
...
}
Note: Since this is a private Set you may be trying to use this from another class, so getAttributes() might be returning a reference to the Set object. In which case my answer may not be useful.
Your code looks fine. Make sure you clean the project and rerun.
What is likely happening is that the type of task is a raw type, of a class that is generic (i.e. it can be parameterized but you didn't parameterize it). If this is the case, I know that logically it shouldn't make a difference on the result of the getAttributes() method; but using raw types "turns off" generics and so it says getAttributes() returns just Set, without its parameter, which causes things you get out of it to be Object.

Categories

Resources